Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: ReactDom.hydrate detects but doesn´t fix diff #11064

Closed
piotrblasiak opened this issue Oct 3, 2017 · 4 comments
Closed

Bug: ReactDom.hydrate detects but doesn´t fix diff #11064

piotrblasiak opened this issue Oct 3, 2017 · 4 comments

Comments

@piotrblasiak
Copy link

piotrblasiak commented Oct 3, 2017

I have an intentional difference in the client vs server rendering: an Image component that displays a different src depending on the screen pixel density:

import React from "react";
import PropTypes from "prop-types";

function Image(props) {
  let src = props.src;
  const { style = {} } = props;
  const width = props.width || style.width;
  const height = props.height || style.height;
  const pixelRatio = global.devicePixelRatio || 1;

  if ((width || height) && pixelRatio > 1) {
    const lastDotIndex = src.lastIndexOf(".");

    if (lastDotIndex !== -1) {
      const name = src.substring(0, lastDotIndex);
      const multiplier = pixelRatio > 2 ? 3 : 2;
      const suffix = src.substring(lastDotIndex, src.length);

      src = `${name}@${multiplier}x${suffix}`;
    }
  }

  return <img {...props} src={src} />;
}

Image.propTypes = {
  src: PropTypes.string.isRequired,
  width: PropTypes.number,
  height: PropTypes.number
};

Image.defaultProps = {
  width: undefined,
  height: undefined
};

export default Image;

What is the current behavior?

When I render this on a retina screen, I get this warning:

Warning: Prop src did not match. Server: "image.png" Client: "[email protected]"

But, the browser shows the server-rendered content, and not the correct client one.

What is the expected behavior?

That the client mutates the dom and changes the src attribute of the img.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?

react 16.0.0 Chrome 61.0.3163.100. In previous versions of react this was not a good approach because render() would then re-render the whole DOM instead of just the diff.

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2017

In my understanding it is not expected to patch up the differences since doing that in production is too expensive and negates the performance benefits from the new approach.

See also #10591 (comment).

@gaearon gaearon closed this as completed Oct 3, 2017
@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2017

(If you intentionally want to render something different on the client, one popular approach is to set a boolean state flag like this.state.hasMounted in componentDidMount, and use that when rendering. This way the initial render pass will be the same as the server, but there will be an additional pass where you change what you want to see on the client.)

@piotrblasiak
Copy link
Author

Ok, thanks. - then I think the docs are a bit misleading or at least unclear:

Same as render(), but is used to hydrate a container whose HTML contents were rendered by ReactDOMServer. React will attach event listeners while preserving as much of the existing DOM as possible. For best results, you should try to render the same content on the server as on the client, with as few differences as possible.

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2017

I agree, would you like to send a PR to make it clearer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants