Skip to content

Commit

Permalink
Fix to prevent updates with PureComponent
Browse files Browse the repository at this point in the history
  • Loading branch information
koba04 committed Aug 22, 2018
1 parent 8bc3635 commit a70fb05
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 0 deletions.
34 changes: 34 additions & 0 deletions packages/enzyme-test-suite/test/ReactWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5066,6 +5066,40 @@ describeWithDOM('mount', () => {
});
});

describeIf(is('>= 15.3'), 'PureComponent', () => {
it('should not update when state and props did not change', () => {
class Foo extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
foo: 'init',
};
}

componentDidUpdate() {}

render() {
return (
<div>
{this.state.foo}
</div>
);
}
}
const spy = sinon.spy(Foo.prototype, 'componentDidUpdate');
const wrapper = mount(<Foo id={1} />);
wrapper.setState({ foo: 'update' });
expect(spy).to.have.property('callCount', 1);
wrapper.setState({ foo: 'update' });
expect(spy).to.have.property('callCount', 1);

wrapper.setProps({ id: 2 });
expect(spy).to.have.property('callCount', 2);
wrapper.setProps({ id: 2 });
expect(spy).to.have.property('callCount', 2);
});
});

describeIf(is('>= 16.3'), 'support getSnapshotBeforeUpdate', () => {
it('should call getSnapshotBeforeUpdate and pass snapshot to componentDidUpdate', () => {
const spy = sinon.spy();
Expand Down
34 changes: 34 additions & 0 deletions packages/enzyme-test-suite/test/ShallowWrapper-spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5437,6 +5437,40 @@ describe('shallow', () => {
});
});

describeIf(is('>= 15.3'), 'PureComponent', () => {
it('should not update when state and props did not change', () => {
class Foo extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
foo: 'init',
};
}

componentDidUpdate() {}

render() {
return (
<div>
{this.state.foo}
</div>
);
}
}
const spy = sinon.spy(Foo.prototype, 'componentDidUpdate');
const wrapper = shallow(<Foo id={1} />);
wrapper.setState({ foo: 'update' });
expect(spy).to.have.property('callCount', 1);
wrapper.setState({ foo: 'update' });
expect(spy).to.have.property('callCount', 1);

wrapper.setProps({ id: 2 });
expect(spy).to.have.property('callCount', 2);
wrapper.setProps({ id: 2 });
expect(spy).to.have.property('callCount', 2);
});
});

describeIf(is('>= 16.3'), 'support getSnapshotBeforeUpdate', () => {
it('should call getSnapshotBeforeUpdate and pass snapshot to componentDidUpdate', () => {
const spy = sinon.spy();
Expand Down
11 changes: 11 additions & 0 deletions packages/enzyme/src/ShallowWrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ class ShallowWrapper {
&& typeof instance.shouldComponentUpdate === 'function'
) {
spy = spyMethod(instance, 'shouldComponentUpdate');
// PureComponent
} else if (instance.isPureReactComponent) {
shouldRender = !isEqual(prevProps, props) || !isEqual(state, instance.state);
}
if (props) this[UNRENDERED] = cloneElement(adapter, this[UNRENDERED], props);
this[RENDERER].render(this[UNRENDERED], nextContext);
Expand Down Expand Up @@ -446,6 +449,11 @@ class ShallowWrapper {
const prevProps = instance.props;
const prevState = instance.state;
const prevContext = instance.context;

if (typeof state === 'function') {
state = state.call(instance, prevState, prevProps);
}

// When shouldComponentUpdate returns false we shouldn't call componentDidUpdate.
// so we spy shouldComponentUpdate to get the result.
let spy;
Expand All @@ -458,6 +466,9 @@ class ShallowWrapper {
&& typeof instance.shouldComponentUpdate === 'function'
) {
spy = spyMethod(instance, 'shouldComponentUpdate');
// PureComponent
} else if (instance.isPureReactComponent) {
shouldRender = !isEqual(prevProps, instance.props) || !isEqual(prevState, state);
}
// We don't pass the setState callback here
// to guarantee to call the callback after finishing the render
Expand Down

0 comments on commit a70fb05

Please sign in to comment.