I am building an Isomorphic Application in React which first renders a component server-side, then takes advantage of React's intelligent re-rendering browser-side.
I have run into a situation where the DOM can become out of sync with the React component's state before React is able to first render browser-side. This can happen when the user is on a slow internet connection, and the react.js
file takes a while to download (which is also the reason I'm building an Isomorphic Application)
Here is an example I put together to show this happening: http://jsfiddle.net/jesstelford/z4o44esb
var TodoItem = React.createClass({
// ...
render: function() {
return (
<label>
<input type="checkbox" defaultChecked={this.state.done} onChange={this.onChange} />
{this.props.name}
</label>
);
}
});
// User toggles checkbox ON here, before React is rendered browser-side
// render using React browser-side
var renderedComponent = React.render(component, document.getElementById('content'));
// Incorrectly outputs { done: false }
console.log('React state:', renderedComponent.state);
I have found one possible solution using React refs
: http://jsfiddle.net/jesstelford/z4o44esb/2
var TodoItem = React.createClass({
// ...
syncStateFromDOM: function() {
this.setDone(this.refs.done.getDOMNode().checked);
},
render: function() {
return (
<label>
<input ref="done" type="checkbox" defaultChecked={this.state.done} onChange={this.onChange} />
{this.props.name}
</label>
);
}
});
// User toggles checkbox ON here, before React is rendered browser-side
// render using React browser-side
var renderedComponent = React.render(component, document.getElementById('content'));
// Sync state from the DOM
renderedComponent.syncStateFromDOM()
// Correctly outputs { done: true }
console.log('React state:', renderedComponent.state);
The downsides to this approach are:
When pre-rendering a React Component server-side, is there any way to sync DOM state to that React Component before it has rendered browser-side, given the DOM has been manipulated by the user before React is loaded browser-side?
Thanks!
React will update the entire Virtual DOM. It'll then compare the Virtual DOM before updating, with the one after updating, to identify what objects have been changed. It uses the Diffing Algorithm. Only the changed objects will get updated on the Real DOM.
In Isomorphic process,when Developer authorizes client facing module ,there is a dependency of the module which requires a file containing secret data,Application is bundled with that file and sent to client with all secret and private data which an attacker can easily access by searching the bundle file .
This is an intriguing question! At a high level, the problem is that React isn't catching the 'change' event that bubbled up to the top-level component when you clicked the checkbox, because it wasn't instantiated yet on the client side. Your half-solution handles this by manually simulating a call to onChange
. I started thinking that you might need to queue onChange events... but then I realized that React already has everything you need.
The "three-quarters" solution is to simply rename syncStateFromDOM
to componentDidMount
, and don't even bother calling it manually. As per the docs, in the most recent versions of React, componentDidMount
is only called in the browser, and it's a lifecycle callback for after the component mounts (i.e. when React.render
is about to return). It's the perfect place for your use case. See: http://jsfiddle.net/qdt4z3w9/
That solves your problem of code external to the component itself! But there's still state-setting going on after the original render takes place. Unfortunately, I think this is fundamentally the way React works - in order to be able to match up existing DOM nodes to refs, each component needs to be fully mounted first. But an extra Virtual DOM diff is a small price to pay, since it's designed to be lightning-quick.
Hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With