Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: in shallow renderer this.state in shouldComponentUpdate will be updated by getDeriveStateFromProps #14607

Closed
chenesan opened this issue Jan 16, 2019 · 0 comments · Fixed by #14613

Comments

@chenesan
Copy link
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant