Redux mapStateToProps多次调用

时间:2017-04-04 09:41:03

标签: reactjs redux react-redux

我有这个非常简单的Component,它连接到redux状态并返回{fruit, vegetables}。一切正常,但我们说我在Component中有一个图表,如果只从API接收更新的vegetable,则每次都会重新创建图表。

这是我的组成部分:

const Products = ({ fruit, vegetable }) =>
  <div className='Products'>
      <div>{vegetable.map(....logic here)}</div>
      <div>{Math.random()}</div> // this is to illustrate the component is rendering every time
      <Graph>Here will be a chart or a graph with fruit</Graph> //but it gets re-rendered even though there is no new fruit
  </div>

const mapStateToProps = (state) => {
  return {
    fruit: state.data.fruit,
    vegetable:  state.data.vegetable,
  }
}

export default connect(mapStateToProps)(Products)

在我看来,无论哪个状态更新,它都会重新呈现整个组件。

有没有办法防止这种情况?

3 个答案:

答案 0 :(得分:6)

当渲染React组件时,它下面的整个组件树也会被渲染 - 除了shouldComponentUpdate hook返回false的组件。因此,在您的情况下,如果Products组件被渲染,Graph组件也是正常的。

这里有两个选项:

  • 如果您的Products组件未使用fruit组件之外的Graph道具,则可以将您的图形组件直接连接到fruit状态,并使用pure函数的connect选项,以避免在fruit未发生变化时重新呈现

  • 您可以在shouldComponentUpdate组件中定义Graph挂钩以手动跳过不必要的渲染,或使用帮助程序库为您执行此操作,例如pure帮助程序recompose

第一个选项是优化react / redux应用程序/避免不必要的渲染通常开始的地方:将组件连接到商店中最低级别的有意义的地方。第二种选择更多的是逃生舱 - 但仍然常常有用。

正如您所提到的,您使用无状态组件,您可以使用更高阶的组件来从shouldComponentUpdate挂钩中受益。要理解它是如何工作的,这里的简单实现如下所示:

function pure(BaseComponent, shouldUpdateFn) {
    return class extends Component {
        shouldComponentUpdate(nextProps) {
            return shouldUpdateFn(this.props, nextProps);
        }
        render() {
            return <BaseComponent { ...this.props } />;
        }
    }
}

这会给你一个pure HOC,你可以在你的app上重复使用它来避免不必要的渲染:它通过将你的无状态组件包装到一个带有所需钩子的新组件中来工作。你可以像这样使用它,例如:

export default pure(Graph, (props, nextProps) => props.fruit !== nextProps.fruit)

尽管如此,我强烈建议您重新考虑重构,其中包含更精细的实现,并避免重新发明轮子。

答案 1 :(得分:2)

要防止组件在接收新道具时重新渲染,您可以在Graph中实施shouldcomponentupdate()

  

使用shouldComponentUpdate()让React知道组件的输出是否不受当前状态或道具更改的影响。默认行为是在每次状态更改时重新呈现,在绝大多数情况下,您应该依赖于默认行为。

     

在收到新的道具或州时,在渲染之前调用shouldComponentUpdate()。默认为true。初始渲染或使用forceUpdate()时不会调用此方法。

     

返回false并不会阻止子组件在状态发生变化时重新呈现。

     

目前,如果shouldComponentUpdate()返回false,则不会调用componentWillUpdate(),render()和componentDidUpdate()。请注意,将来React可能会将shouldComponentUpdate()视为提示而不是严格的指令,并且返回false仍可能导致重新呈现组件。

     

如果在分析后确定特定组件的速度很慢,则可以将其更改为从React.PureComponent继承,该实现具有浅的prop和状态比较的shouldComponentUpdate()。如果您确信要手动编写它,可以将this.props与nextProps和this.state与nextState进行比较,并返回false告诉React可以跳过更新。

为了帮助您实施shouldComponentUpdate(),您可以使用React shallow-compare()或自定义浅比较功能

答案 2 :(得分:2)

鉴于您当前的代码。 当状态改变时,React将更新整个组件。 因此Graph Component将会更新。

如果您不希望图形组件得到更新,您可以在图表组件中添加 shouldComponentUpdate ,并在那里引入检查以重新呈现,如下所示

shouldComponentUpdate: function(nextProps, nextState) {
    // You can access `this.props` and `this.state` here
    // and check them against nextProps and nextState respectively.
    // return boolean(false) if you don't want the component to re-render.
  }