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

calling setState in componentDidUpdate of a PureComponent causes an infinite loop #2096

Closed
1 of 3 tasks
joseph-bakke opened this issue Apr 12, 2019 · 4 comments
Closed
1 of 3 tasks
Assignees
Labels

Comments

@joseph-bakke
Copy link

joseph-bakke commented Apr 12, 2019

Current behavior

A PureComponent that fires setState in componentDidUpdate with no changes to the state values enters an infinite loop if the component has more than one state property.

Expected behavior

componentDidUpdate should not be called if there are no changes to the state property values regardless of the number of state properties.

Investigation

I dug into this a bit to figure out what was going on, and I think I found the crux of the issue.

At ShallowWrapper:781 statePayload is being passed to pureComponentShouldComponentUpdate.

The issue is that statePayload is only the object passed to setState, not the result of the next state update, so the shallowEqual check will always fail.

In the below example the statePayload value would be

{ secondValue: false }

Then the shallowEquals check would be as follows, which would always fail.

!shallowEqual({firstValue: false, secondValue: false}, {secondValue: false})

The check should be

!shallowEqual({firstValue: false, secondValue: false}, {firstValue: false, secondValue: false})

Example Test:

class Example extends PureComponent {
  constructor(props) {
    super(props);

    this.state = {
      firstValue: false,
      secondValue: false,
    };
  }

  componentDidMount() {
    this.setState({secondValue: false});
  }

  componentDidUpdate() {
    this.setState({secondValue: false});
  }

  render() {
    return React.createElement('div', null, this.state.firstValue + ' ' + this.state.secondValue);
  }
}

it('should not go crazy', () => {
  expect(() => {
    shallow(React.createElement(Example));
  }).not.toThrow();
});

Your environment

API

  • shallow
  • mount
  • render

Version

library version
enzyme 3.9
react 16.8.6
react-dom 16.8.6
react-test-renderer 16.8.6
adapter (below)
jest 24.7.1

Adapter

  • [ x ] enzyme-adapter-react-16
@joseph-bakke
Copy link
Author

I'm happy to take a whack at fixing this, but I wanted to file an issue first and get confirmation from someone with a little more familiarity that this is indeed a bug before opening a PR :).

@ljharb
Copy link
Member

ljharb commented Apr 13, 2019

Thanks, enzyme has to wrap component setStates in order to update properly, and it's likely we need extra handling for PureComponent. A PR would be great!

@hugomallet
Copy link

Hi,

I still have this bug with 3.10.0. Is the fix already merged ?

@ljharb
Copy link
Member

ljharb commented Jul 16, 2019

yes, and released. Please file a new issue if you’re still having trouble.

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

No branches or pull requests

3 participants