2

If a stateful react component C is at position P in VDOM V at time T

then

where will C be in VDOM V' at time T+1 after a re-render ?

For example in this fiddle the state of the first stateful component is "transferred" to the second stateful component when the parent prop changes from true to false. Also the second component's state gets lost when switching back. How can this be explained ? Are the rules documenting this behaviour available somewhere ? Here it is not described very accurately.

jhegedus
  • 20,244
  • 16
  • 99
  • 167

1 Answers1

1

You have a view that renders like this.

<MyComponent />

Now, if this view was to be re-rendered multiple times (leading to the same state/lifecycle, or what you call a transfer, which is not quite the word I'd use, between each render), then the below conditions are true.

  • Is it the same component type (the tag name: <MyComponent />) in this render tree as the last one?
  • Is the component in the same place as last time, same parent etc?
  • If the component had a key attribute assigned to it in the last render, is it in the next render tree under the same parent as last time, with the same key value?

Imagine a complete render tree in below pseudo code:

<div id="awesome-container">
    <Parent>
        { randomBoolean ? <AlphaChild /> : <BetaChild /> }
    </Parent>
</div>

Alpha and Beta components will always unmount when they get replaced with another one, and their state will be "reset", aka they will get mounted as new components.

Looking at the above example, you may think of it all as "unresolved HTML". The custom tags are not the final product of what's in the DOM. Instead, when resolved, it looks more like this:

<div id="awesome-container"> // just an element, is stateless
    <div class="parent"> // has a lifecycle/state tied to it
         <span name="alpha"> // also has a lifecycle/state
             <p>My job is to show the time: 10:00 AM</p>
         </span>
    </div>
</div>

If AlphaChild was suddenly replaced with BetaChild, there'd be no point to keep the AlphaChild state/lifecycle around, right? And if we did want to keep it around, we are likely keeping some data which is way too important for a mere child in a list to maintain (A smart component / parent, or Redux, comes to mind). You could always just hide the component too using CSS, just to preserve the state.

And if we didn't have keys, we wouldn't be able to switch the components around.

constructor() {
this.state = { components: [ <AlphaChild />, <BetaChild />, <CharlieChild /> ] };
}

someEvent() {
    // Moves the first element in the array to the last position.
    this.setState({ 
        this.state.components: [this.components.slice(1)].push(this.state.components[0]))
    }
}

render() {
    { this.state.components }
}

Whatever order the components above resulted in, for example:

<BetaChild /> // has state
<AlphaChild /> // has state
<CharlieChild /> // has state

The state would be killed off between each re-ordering of the components.

<AlphaChild /> // has completely new state
<CharlieChild /> // has completely new state
<BetaChild /> // has completely new state

That's why keys are very important in react, to keep state in a list that is very likely to be re-ordered.

There isn't much more than that to keep track of. If a component gets removed from its parent and appears somewhere else in the code, it will not keep its old state/lifecycle because it is far from obvious that they are the same. In fact, there's no logical way that tells us that is the case. Not even with keys, because keys can be part of any multiple lists in the rendering process.

I hope this makes things a tad more clear. If you want to learn more about virtual DOM, I suggest checking out Snabbdom on github. They don't keep component lifecycles for you, so you'd need to figure it out yourself. Snabbmitt could be useful to check out for inspirational purposes.

Generally though, I think you don't need to bother too much reading about the virtual DOM, just follow the principles and you should be OK.

William Bernting
  • 561
  • 4
  • 15
  • 1
    Wow, thank you for the detailed answer, I need to go through it carefully and take my time to understand it. – jhegedus Jun 03 '17 at 03:08
  • No problem! I will update my answer if you have additional questions in this comment area. When you are ready, please mark my answer as accepted. Thanks! – William Bernting Jun 03 '17 at 06:38
  • So to summarize, there are two ways a component can keep its state (identity) : 1) type + tree path to parent + position amongs siblings is the same between re-renders, 2) type + tree path to parent + key value is same (position among siblings can change) among re-renders. So no matter how siblings change/are reordered if there is the same key, same path, same type for a component then it wild keep its state ? – jhegedus Jun 03 '17 at 19:57