I'm trying to use react-select and got an error throw document is not defined. I assume this is because it's trying to render the component on the server side and there's no document.
What's the best way to only render a specific component only on the client side?
Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
I think you need to have an container in your HTML and then call renderToString with this target in the componentDidMountmethod which will only be called on client siede
You can either fake that document object on the server to trick that component. E.g. if component is using window.addEventListener(...). You can create the following global var:
import emptyFunction from 'fbjs/lib/emptyFunction';
global.window = {
addEventListener: emptyFunction,
removeEventListener: emptyFunction
};
Or, even better, don't render that component on the server, e.g.:
import { canUseDOM } from 'fbjs/lib/ExecutionEnvironment';
class MyComponent {
render() {
return (
<div>
{ canUseDOM && React.createElement(require('react-select')) }
</div>
);
}
}
Or, contact the 3rd party component's author and ask to add server-side rendering support.
thx @koistya I think that is a much better solution than using componentDidMount!
I tried the canUseDOM solution and it worked for me. However it is showing a warning, invalid checksum about the markup being generated is different on the client. I think this means React redraws the markup on the client-side.
Is it possible to get rid of this warning?
i tried canUseDOM solution and turn out {canUseDOM ? React.createElement(rte.default):"Rendering"} as my 'rte.js' export default class rte
leave this just for someone who later encounters the problem like me
I tried the canUseDOM solution and it worked for me. However it is showing a warning, invalid checksum about the markup being generated is different on the client. I think this means React redraws the markup on the client-side.
I also ran into this issue. As a way to resolve it used a state variable to ensure the client-side only module is rendered after the first render, like this:
import React, { PropTypes } from 'react';
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {appIsMounted: false};
}
componentDidMount() {
requestAnimationFrame(() => {
this.setState({ appIsMounted: true });
});
}
render() {
return (
<div>
{ this.state.appIsMounted
&& React.createElement(
require('../../client-side-only').default
)
}
</div>
);
}
}
Hope this helps somebody else...
This is one which should be mentioned in the docs. There is no DOM on server.
PRs welcomed!
Most helpful comment
I also ran into this issue. As a way to resolve it used a state variable to ensure the client-side only module is rendered after the first render, like this:
Hope this helps somebody else...