Did you ever wonder what happens to a component’s props when
React instantiates the component class? And then, what happens
to props if the parent re-renders the component with different
properties?
The spy component
Let’s create a spy so that we can check what’s going on.
1import React from 'react';
2import shallowCompare from 'react-addons-shallow-compare';
3
4let spyConstructors = [];
5let spyRenders = [];
6
7export default class Spy extends React.Component {
8 constructor (props) {
9 super (props);
10 spyConstructors.push ({obj: this, props: this.props});
11 }
12 shouldComponentUpdate (nextProps, nextState) {
13 return shallowCompare (this, nextProps, nextState);
14 }
15 getText () {
16 return 'Text:' + this.props.text;
17 }
18 render () {
19 spyRenders.push ({obj: this, props: this.props});
20 return <div id={this.props.id}>{this.props.text}</div>;
21 }
22
23 static clear () {
24 spyConstructors = [];
25 spyRenders = [];
26 }
27
28 static getConstructorLog () {
29 return spyConstructors;
30 }
31
32 static getRenderLog () {
33 return spyRenders;
34 }
35}
The test code
We’ll use the <Spy> like so:
1Spy.clear ();
2ReactDOM.render (<Spy text='a'/>, mountNode);
3ReactDOM.render (<Spy text='b'/>, mountNode);
4const constr = Spy.getConstructorLog ();
5const render = Sky.getRenderLog ();
and observe what happens to the props which get passed into
the constructor, and then used by the render() method.
Results
In my test code, there will be only one component instanciation.
React is smart enough to reuse the same <Spy> element. We can
check this with:
1expect (constr).to.have.length (1);
And naturally, there will be two calls to render(), since
shouldComponentUpdate will return true when switching
from text='a' to text='b':
1expect (render).to.have.length (2);
We can verify that the same component instance was used:
1expect (constr[0].obj).to.equal (render[0].obj);
2expect (constr[0].obj).to.equal (render[1].obj);
And what about the props?
Well, the props change between the first and the second
call to ReactDOM.render, so the element’s props will
be replaced:
1expect (constr[0].props).to.equal (render[0].props);
2expect (constr[0].props).to.not.equal (render[1].props);
That’s about what we should expect. Changing the properties
should indeed inject other props into the <Spy>, and this
is what happens.
React provides a lifecycle method called componentWillReceiveProps()
which gets called before the props change. See React component specs
for further the details.