多次调用 Redux mapStateToProps
Redux mapStateToProps called multiple times
我有这个非常简单的组件,它连接到 redux state 和 returns {fruit, vegetables}
。一切正常,但假设我在组件内有一个图表,如果我只从 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)
在我看来,无论更新哪个状态,它都会重新渲染整个组件。
有什么办法可以避免吗?
要防止组件在接收新道具时重新渲染,您可以在 Graph
中实现 shouldcomponentupdate()
。
Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.
shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.
Returning false does not prevent child components from re-rendering when their state changes.
Currently, if shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate() will not be invoked. Note that in the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still result in a re-rendering of the component.
If you determine a specific component is slow after profiling, you may change it to inherit from React.PureComponent which implements shouldComponentUpdate() with a shallow prop and state comparison. If you are confident you want to write it by hand, you may compare this.props with nextProps and this.state with nextState and return false to tell React the update can be skipped.
为了帮助您实施 shouldComponentUpdate()
,您可以使用 React shallow-compare()
或自定义浅层比较函数
当一个 React 组件被渲染时,它下面的整个组件树也会被渲染 - shouldComponentUpdate
挂钩 returns false
的组件除外。因此,在您的情况下,如果 Products
组件被渲染,那么 Graph
组件也渲染是正常的。
这里有两个选择:
如果您的 Products
组件不在 Graph
组件之外使用 fruit
道具,您可以直接将您的 Graph 组件连接到 fruit
状态,并使用connect
函数的pure
选项,避免在fruit
不改变
时重新渲染
您可以在 Graph
组件中定义 shouldComponentUpdate
挂钩以手动跳过不必要的渲染,或使用帮助程序库为您完成此操作,例如 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,你可以在你的应用程序中重用它来避免不必要的渲染:它的工作原理是将你的无状态组件包装到一个带有所需钩子的新组件中。您可以像这样使用它,例如:
export default pure(Graph, (props, nextProps) => props.fruit !== nextProps.fruit)
不过,我强烈建议您看看 recompose,它对此有更细粒度的实现,并且可以避免您重新发明轮子。
鉴于您当前的代码。
当状态改变时,React 将更新整个组件。
因此图形组件将得到更新。
如果您不想更新图形组件,您可以在图形组件中添加 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.
}
我有这个非常简单的组件,它连接到 redux state 和 returns {fruit, vegetables}
。一切正常,但假设我在组件内有一个图表,如果我只从 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)
在我看来,无论更新哪个状态,它都会重新渲染整个组件。
有什么办法可以避免吗?
要防止组件在接收新道具时重新渲染,您可以在 Graph
中实现 shouldcomponentupdate()
。
Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.
shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.
Returning false does not prevent child components from re-rendering when their state changes.
Currently, if shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate() will not be invoked. Note that in the future React may treat shouldComponentUpdate() as a hint rather than a strict directive, and returning false may still result in a re-rendering of the component.
If you determine a specific component is slow after profiling, you may change it to inherit from React.PureComponent which implements shouldComponentUpdate() with a shallow prop and state comparison. If you are confident you want to write it by hand, you may compare this.props with nextProps and this.state with nextState and return false to tell React the update can be skipped.
为了帮助您实施 shouldComponentUpdate()
,您可以使用 React shallow-compare()
或自定义浅层比较函数
当一个 React 组件被渲染时,它下面的整个组件树也会被渲染 - shouldComponentUpdate
挂钩 returns false
的组件除外。因此,在您的情况下,如果 Products
组件被渲染,那么 Graph
组件也渲染是正常的。
这里有两个选择:
如果您的
Products
组件不在Graph
组件之外使用fruit
道具,您可以直接将您的 Graph 组件连接到fruit
状态,并使用connect
函数的pure
选项,避免在fruit
不改变 时重新渲染
您可以在
Graph
组件中定义shouldComponentUpdate
挂钩以手动跳过不必要的渲染,或使用帮助程序库为您完成此操作,例如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,你可以在你的应用程序中重用它来避免不必要的渲染:它的工作原理是将你的无状态组件包装到一个带有所需钩子的新组件中。您可以像这样使用它,例如:
export default pure(Graph, (props, nextProps) => props.fruit !== nextProps.fruit)
不过,我强烈建议您看看 recompose,它对此有更细粒度的实现,并且可以避免您重新发明轮子。
鉴于您当前的代码。 当状态改变时,React 将更新整个组件。 因此图形组件将得到更新。
如果您不想更新图形组件,您可以在图形组件中添加 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.
}