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
srcdid 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.
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 https://github.com/facebook/react/issues/10591#issuecomment-326635627.
(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.)
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.
I agree, would you like to send a PR to make it clearer?