React: PureComponent's shallowEqual

Created on 23 Aug 2018  路  7Comments  路  Source: facebook/react

class App extends React.PureComponent {
  state={
    ele: {a:'1'}
  }
  trigger=()=>{
    console.log('click')
    this.setState({ele: {a:'1'}})
  }
  render() {
    console.log('render')
    return (
      <div onClick={this.trigger}>click here to trigger setState</div>
    );
  }
}

A simple demo shows that click event triggers render every time.
demo

However, according to source code, React.PureComponent鈥檚 shouldComponentUpdate() shallowly compares the objects like following, the click event shouldn't trigger render.

Performs equality by iterating through keys on an object and returning false when any key has values which are not strictly equal between the arguments. Returns true when the values of all keys are strictly equal.

Most helpful comment

If you mean individual properties, afaik they're compared using Object.is algorithm (which is slightly different from === because it also handles NaN).

All 7 comments

PureComponent shallow equal is related to _props_ not state, it will not re-render if the props passed to the component are shallowly equal to the previous ones. It doesn't check that state values are equal.

If it did compare state however, your example would still nto work because its not shallowly equal, elem's value is a new object every set, so prevState.elem !== nextState.elem

PureComponent shallow equal is related to props not state,

This is not correct, the doc says " it with a shallow prop and state comparison."

Or just from the src code https://github.com/facebook/react/blob/0beb2ee76b96ffb1c15a1770a6907ea1cd5a5696/packages/react-reconciler/src/ReactFiberClassComponent.js#L261 is same

Oops, yes your right :P not thinking clearly. The second point still holds, it's not shallow ly equal in your example

/**
 * Performs equality by iterating through keys on an object and returning false
 * when any key has values which are not strictly equal between the arguments.
 * Returns true when the values of all keys are strictly equal.
 */
function shallowEqual(objA: mixed, objB: mixed): boolean {
  if (is(objA, objB)) {
    return true;
  }

  if (typeof objA !== 'object' || objA === null ||
      typeof objB !== 'object' || objB === null) {
    return false;
  }

  const keysA = Object.keys(objA);
  const keysB = Object.keys(objB);

  if (keysA.length !== keysB.length) {
    return false;
  }

  // Test for A's keys different from B.
  for (let i = 0; i < keysA.length; i++) {
    if (
      !hasOwnProperty.call(objB, keysA[i]) ||
      !is(objA[keysA[i]], objB[keysA[i]])
    ) {
      return false;
    }
  }

  return true;
}

PureComponent shallow equal is related to state, have wrote a demo to prove. Also, shallowEqual is not just like '===', see source code above.

this.state is not shallowly equal to prevState because this.state.ele and prevState.ele are two different objects. Therefore the shallow equality check fails.

@gaearon Actually I just want to know is there any difference between PureComponent's shallowEqual and '===', because according to the src code there is.

If you mean individual properties, afaik they're compared using Object.is algorithm (which is slightly different from === because it also handles NaN).

Was this page helpful?
0 / 5 - 0 ratings