Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Redux Containers Demystified

Redux Containers Demystified

A look into react-redux's connect function and how it decides if your connected component should re-render or not.

Mike Klemarewski

January 25, 2018
Tweet

More Decks by Mike Klemarewski

Other Decks in Programming

Transcript

  1. AGENDA - Build an app that re-renders components when it

    shouldn't - Gain an understanding of when connected components re-render - Fix our bug!
  2. TASK > Build a car configurator > Able to customize

    anything about the car > Torsla is fun. Use lots of color!
  3. AGENDA - Build an app that re-renders components when it

    shouldn't - Gain an understanding of when connected components re-render - Fix our bug!
  4. CONNECTED COMPONENT - Every time the redux store changes: -

    Check some stuff to see if we need to render
  5. REACT-REDUX SOURCE CODE function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged =

    !areOwnPropsEqual(nextOwnProps, ownProps) const stateChanged = !areStatesEqual(nextState, state) state = nextState ownProps = nextOwnProps if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps }
  6. REACT-REDUX SOURCE CODE function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged =

    !areOwnPropsEqual(nextOwnProps, ownProps) const stateChanged = !areStatesEqual(nextState, state) state = nextState ownProps = nextOwnProps if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps }
  7. CONNECTED COMPONENT - Every time the store changes: - Run

    the selector - ownProps change: re-render
  8. REACT-REDUX SOURCE CODE function handleSubsequentCalls(nextState, nextOwnProps) { const propsChanged =

    !areOwnPropsEqual(nextOwnProps, ownProps) const stateChanged = !areStatesEqual(nextState, state) state = nextState ownProps = nextOwnProps if (propsChanged && stateChanged) return handleNewPropsAndNewState() if (propsChanged) return handleNewProps() if (stateChanged) return handleNewState() return mergedProps }
  9. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  10. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  11. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  12. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  13. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  14. REACT-REDUX SOURCE CODE function handleNewState() { const nextStateProps = mapStateToProps(state,

    ownProps) const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps) stateProps = nextStateProps if (statePropsChanged) mergedProps = mergeProps(stateProps, dispatchProps, ownProps) return mergedProps }
  15. CONNECTED COMPONENT - Every time the store changes: - Run

    the selector - ownProps change: re-render - stateProps change: re-render
  16. CONNECTED COMPONENT - Every time the store changes: - Run

    the selector - ownProps change: re-render - !areStatePropsEqual(nextStateProps, stateProps)
  17. areStatePropsEqual -> shallowEqual - Checks that each object has the

    same number of keys - Checks that each key is === to the previous value
  18. === FALSE { a: 'a' } === { a: 'a'

    } [1, 2, 3] === [1, 2, 3]
  19. === For objects, === checks that the references are the

    same const a = { a: 'a' } a === { a: 'a' } // false a === a // true
  20. OUR MAP STATE TO PROPS function mapStateToProps(state) { return {

    count: state.wheels.get('count'), price: getPriceForWheels(state), } }
  21. OUR MAP STATE TO PROPS function mapStateToProps(state) { return {

    count: state.wheels.get('count'), price: getPriceForWheels(state), } }
  22. OUR MAP STATE TO PROPS function mapStateToProps(state) { return {

    count: state.wheels.get('count'), price: getPriceForWheels(state), } } > returns an object! > shallow equal check in the connect function fails > component re-renders!
  23. AGENDA - Build an app that re-renders components when it

    shouldn't - Gain an understanding of when connected components re-render - Fix our bug!
  24. WE COULD ONLY RETURN PRIMITIVES function mapStateToProps(state) { const {

    price, currency } = getPriceForWheels(state); return { price, currency, count: state.seatbelts.get('count'), } }
  25. WE CAN MEMOIZE OBJECT REFERENCES > return the same object

    reference if it has not changed > Reselect can help with this > same reference returned, container does not re-render
  26. TO SUMMARIZE when redux store changes, for each connected component:

    run mapStateToProps for that component, shallow compare it's return value to the last value if it changed: re-render