You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
ShallowWrapper uses lodash.isequal in the shouldComponentUpdate implementation of PureComponents. This is causing some minor discrepancy between React and Enzyme since _.isEqual performs a deep equality check whereas React, I believe, performs a shallow comparison on each member of the props/state objects. I'd imagine this has some performance implications as well.
I noticed this in a unit test when shallow rendering a PureComponent whose state uses ImmutableJS for some parts of it. In my unit test (and not in the actual web app), I was getting some unwanted warnings from ImmutableJS that were caused by the deep equality checks.
Test stack trace
console.warn node_modules/immutable/dist/immutable.js:4637
iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
at src_Map__Map.get (/home/travis/build/project/project/node_modules/immutable/dist/immutable.js:4632:21)
at isArrayLike (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1588:42)
at keys (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1806:10)
at baseGetAllKeys (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:883:16)
at getAllKeys (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1286:10)
at equalObjects (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1216:18)
at baseIsEqualDeep (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:994:10)
at baseIsEqual (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:935:10)
at equalObjects (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1253:39)
at baseIsEqualDeep (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:994:10)
at baseIsEqual (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:935:10)
at isEqual (/home/travis/build/project/project/node_modules/lodash.isequal/index.js:1639:10)
at pureComponentShouldComponentUpdate (/home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:169:82)
at /home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:599:30
at withSetStateAllowed (/home/travis/build/project/project/node_modules/enzyme/build/Utils.js:326:3)
at ShallowWrapper.<anonymous> (/home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:576:42)
at ShallowWrapper.single (/home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:1830:25)
at ShallowWrapper.setState (/home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:575:14)
at Component.ShallowWrapper.instance.setState (/home/travis/build/project/project/node_modules/enzyme/build/ShallowWrapper.js:217:35)
Also, I haven't really dived into the enzyme code prior to this, so apologies if I'm misunderstanding how ShallowWrapper works :)
Test case
In the tests at the bottom of the sample code, I'd have expected both test cases to pass (but only the second does). When I put this component into an existing app, I see the componentDidUpdate does get called when clicking on either button.
importReact,{PureComponent}from'react';exportdefaultclassTestextendsPureComponent{state={a: {b: {c: 1}}};componentDidUpdate(prevProps,prevState){this.props.onUpdate();}// this should still trigger a re-render even though they have deep equality, but doesnt in enzymehandleClick=()=>{this.setState({a: {b: {c: 1}}});};handleStateChangeClick=()=>{this.setState({a: {b: {c: 2}}});};render(){return(<div><buttondata={1}onClick={this.handleClick}>
No State Change
</button><buttondata={2}onClick={this.handleStateChangeClick}>
State Change
</button></div>);}}test('it re-renders when setState is called even if the object has deep equality to the existing state',()=>{constupdateSpy=jest.fn();constwrapper=shallow(<TestonUpdate={updateSpy}/>);wrapper.find('button[data=1]').simulate('click');expect(updateSpy).toHaveBeenCalledTimes(1);});test('it re-renders when setState is called with an object that doesnt have deep equality',()=>{constupdateSpy=jest.fn();constwrapper=shallow(<TestonUpdate={updateSpy}/>);wrapper.find('button[data=2]').simulate('click');expect(updateSpy).toHaveBeenCalledTimes(1);});
Expected behavior
ShallowWrapper uses a shallow comparison as opposed to a deep comparison for its pureComponentShouldComponentUpdate check.
Your environment
API
shallow
mount
render
Version
library
version
enzyme
3.7.0
react
16.6.0
react-dom
16.6.0
react-test-renderer
16.6.0
adapter (below)
Adapter
enzyme-adapter-react-16
enzyme-adapter-react-16.3
enzyme-adapter-react-16.2
enzyme-adapter-react-16.1
enzyme-adapter-react-15
enzyme-adapter-react-15.4
enzyme-adapter-react-14
enzyme-adapter-react-13
enzyme-adapter-react-helper
others ( )
The text was updated successfully, but these errors were encountered:
For reference, here's React's shallowEqual helper used in shouldComponentUpdate of PureComponent:
functionshallowEqual(objA: mixed,objB: mixed): boolean{if(is(objA,objB)){returntrue;}if(typeofobjA!=='object'||objA===null||typeofobjB!=='object'||objB===null){returnfalse;}constkeysA=Object.keys(objA);constkeysB=Object.keys(objB);if(keysA.length!==keysB.length){returnfalse;}// Test for A's keys different from B.for(leti=0;i<keysA.length;i++){if(!hasOwnProperty.call(objB,keysA[i])||!is(objA[keysA[i]],objB[keysA[i]])){returnfalse;}}returntrue;}
Current behavior
ShallowWrapper
useslodash.isequal
in the shouldComponentUpdate implementation of PureComponents. This is causing some minor discrepancy between React and Enzyme since_.isEqual
performs a deep equality check whereas React, I believe, performs a shallow comparison on each member of the props/state objects. I'd imagine this has some performance implications as well.I noticed this in a unit test when shallow rendering a PureComponent whose state uses ImmutableJS for some parts of it. In my unit test (and not in the actual web app), I was getting some unwanted warnings from ImmutableJS that were caused by the deep equality checks.
Test stack trace
Also, I haven't really dived into the enzyme code prior to this, so apologies if I'm misunderstanding how ShallowWrapper works :)
Test case
In the tests at the bottom of the sample code, I'd have expected both test cases to pass (but only the second does). When I put this component into an existing app, I see the
componentDidUpdate
does get called when clicking on either button.Expected behavior
ShallowWrapper uses a shallow comparison as opposed to a deep comparison for its
pureComponentShouldComponentUpdate
check.Your environment
API
Version
Adapter
The text was updated successfully, but these errors were encountered: