Description
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
In react-test-renderer/shallow
, the shallow renderer will set instance state in getDerviedStateFromProps
so the this.state
and nextState
will be the same in shouldComponentUpdate
, which is different with the behavior of real rendering.
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below:
given below class component:
class SimpleComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.value,
};
}
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.value === prevState.value) {
return null;
}
return { value: nextProps.value };
}
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldUpdate:', nextState.value !== this.state.value)
return nextState.value !== this.state.value;
}
render() {
return <div className={this.state.value} />;
}
}
render with ReactDOM, the shouldComponentUpdate
will return true since this.state
will be the old value initial
:
const divRef = React.createRef()
const div = document.createElement('div')
// in real test code we have to add a `ref={divRef}` in the `div` of SimpleComponent
const initialResult = ReactDOM.render(<SimpleComponent value="initial" />, div);
expect(divRef.current.classList[0]).toEqual("initial");
// will output `shouldUpdate: true`
const updatedResult = ReactDOM.render(<SimpleComponent value="updated" />, div);
// so the class name changes
expect(divRef.current.classList[0]).toEqual("updated");
In shallow renderer, the behavior is different:
const shallowRenderer = createRenderer();
const initialResult = shallowRenderer.render(<SimpleComponent value="initial" />);
expect(initialResult).toEqual(<div>value:initial</div>);
// will not update, since in `shouldComponentUpdate` the `this.state` has been updated
// after `getDeriveStateFromProps` and as same as passed `nextState`
const updatedResult = shallowRenderer.render(<SimpleComponent value="updated" />);
// the following assert will fail
expect(updatedResult).toEqual(<div>value:updated</div>);
What is the expected behavior?
ShallowRenderer should not set the instance state in getDeriveStateFromProps, or in the shouldComponentUpdate
we have no way to compare it.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
I have tested this in master branch and 16.3, both not work.
By the way this problem is related to enzymejs/enzyme#1970 . If it's recoginzed as a bug I can provide a PR in next several days.