reduxjs / react-redux

Official React bindings for Redux
https://react-redux.js.org
MIT License
23.37k stars 3.37k forks source link

Specifying mergeProps causes impure connected components to not update #337

Closed DouglasLivingstone closed 8 years ago

DouglasLivingstone commented 8 years ago

When an impure connected component is re-rendered due to its parent's state changing, its shouldComponentUpdate returns true, but if a non-default mergeProps is supplied then checkMergedEquals will also be true, causing the component to only update if its nextMergedProps have changed from the previous mergedProps.

In this JSFiddle example, I would expect the root component's setState to trigger a re-render of the PartComponent and both of the impure components, but since the second impure component has a custom mergeProps, it doesn't update.

let store = Redux.createStore(() => ({}))

class PartComponent extends React.Component {
  render() {
    return <span>{ new Date().getTime() }</span>
  }
}

const Impure_DefaultMerge_Connected_PartComponent = ReactRedux.connect(
    null, null, null, { pure: false }
)(PartComponent)

const Impure_CustomMerge_ConnectedPartComponent = ReactRedux.connect(
    null, null, () => ({}), { pure: false }
)(PartComponent)

const Pure_DefaultMerge_ConnectedPartComponent = ReactRedux.connect(
    null, null, null, { pure: true }
)(PartComponent)

const Pure_CustomMerge_ConnectedPartComponent = ReactRedux.connect(
    null, null, () => ({}), { pure: true }
)(PartComponent)

class RootComponent extends React.Component {
  render() {
    return <div>
        <PartComponent /> PartComponent <br />
        <Impure_DefaultMerge_Connected_PartComponent /> Impure_DefaultMerge_Connected_PartComponent <br />
        <Impure_CustomMerge_ConnectedPartComponent /> Impure_CustomMerge_ConnectedPartComponent <br />
        <Pure_CustomMerge_ConnectedPartComponent /> Pure_CustomMerge_ConnectedPartComponent <br />
        <Pure_DefaultMerge_ConnectedPartComponent /> Pure_DefaultMerge_ConnectedPartComponent <br />
      </div>
  }
  componentDidMount() {
    setInterval(() => this.setState({}), 777)
  }
}

ReactDOM.render(
  <ReactRedux.Provider store={store}>
    <RootComponent />
  </ReactRedux.Provider>,
  document.getElementById('container')
)
gaearon commented 8 years ago

Fixed in 4.4.2.