TL;DR: Can I trust the reconciliation algorithm not to re-instantiate my stateful component simply because the change in Virtual DOM was too complicted to keep track of it?
I believe, that React.Component instances are created and destroyed by React run-time to match the shape of Virtual DOM. As a programmer I declaratively describe the Virtual DOM, and the life cycle of instances is controlled by the React itself. I understand that a special reconciliation algorithm tries hard to reuse as much of old instances as possible when the Virtual DOM changes its shape. Also, I understand that if the only difference is in props, then an old instance simply gets its props updated and informed about it via lifecycle methods.
I also expect that for functional components which simply map props to Virtual DOM there is no point in talking about lifecycle, as it does not really matter if this is the same or not the same instance. In particular one does not have to trust the reconciliation algorithm to be very smart, as the component would look and behave the same regardless of if it is the same instance with updated props, or a fresh instance.
But can I, and should I, trust the reconciliation algorithm in case of stateful components?
Say, that I have a component which stores some data in its state and directly on its instance. Moreover, let's assume that the constructor of this component initializes both of them:
constructor(props) {
super(props);
this.state = {
value: ''
};
this.length = 0;
}
Also, assume that the state evolves in time, say, because of user actions
onChange = (e) => {
this.setState({value: e.target.value}
this.length = e.target.value.length;
}
Can I, or can I not, assume that this instance will not get killed and reconstructed on a whim of the React framework? The above component is not "functional", as it has an inner state, which as a developer I presume to be somehow "preserved" even if something complicated happens in the higher part of the components tree during reconciliation.
From the many examples in the docs and the web, I understand, that the community assumes, that the state and private properties of the instance are not reset, unless the parent explicitly changes the key
property, or gets rid of the child, and instantiates a new one later on. But are these assumptions explicitly stated in the docs?
And the question in the other way round: is changing a key
of a child guaranteed to make a new instance, or can react decide to reuse some old instance with a different key (thus reusing its state as well)? In other words: is the key trick guaranteed to work or is it just a hack?
EDIT An example of a problematic situation: https://codesandbox.io/s/9rqrPJnLD. Here we have a stateful component:
class Stateful extends React.Component{
state = { now: new Date()};
render(){
return <div>{this.state.now.toString()}</div>
}
}
living in a hostile environment, of a parent who often changes mind about the layout, and the child is sometimes nested in a div, and sometimes not:
class App extends React.Component{
state = { div: true}
componentDidMount(){
setInterval(()=>{
this.setState(state => {
return {div: !state.div}
});
},2000)
}
render(){
return React.createElement(this.state.div ? 'div' : 'span',null,React.createElement(Stateful))
}
}
It seems that the child is re-instantiated each time the parent changes layout, and the state is not preserved when it happens. This partially answers my own question. The unanswered part being: what are the other cases which are difficult for the reconciliation algorithm.