我对 React 的 shouldComponentUpdate
(未覆盖时)有疑问。我确实更喜欢纯函数组件,但我担心它每次都会更新,即使 props/state 没有改变。所以我正在考虑改用 PureComponent 类。
我的问题是:功能组件是否具有相同的 shouldComponentUpdate
检查为 PureComponents?还是每次都更新?
原文由 MoeSattler 发布,翻译遵循 CC BY-SA 4.0 许可协议
我对 React 的 shouldComponentUpdate
(未覆盖时)有疑问。我确实更喜欢纯函数组件,但我担心它每次都会更新,即使 props/state 没有改变。所以我正在考虑改用 PureComponent 类。
我的问题是:功能组件是否具有相同的 shouldComponentUpdate
检查为 PureComponents?还是每次都更新?
原文由 MoeSattler 发布,翻译遵循 CC BY-SA 4.0 许可协议
功能组件将在每次父级渲染时重新渲染,无论 props 是否已更改。
但是,使用 React.memo
高阶组件,功能组件实际上有可能获得相同的 shouldComponentUpdate
检查哪个用于 PureComponent
https://react– 。 org/docs/react-api.html#reactmemo
您可以简单地将您的功能组件包装在 React.memo
导出时如此处所示。
所以
const SomeComponent = (props) => (<div>HI</div>)
export default SomeComponent
可以改为
const SomeComponent = (props) => (<div>HI</div>)
export default React.memo(SomeComponent)
例子
以下示例显示这如何影响重新渲染
父组件只是一个常规的功能组件。它使用新的 反应钩子 来处理一些状态更新。
它只有一些 tick
状态,仅用于提供一些关于我们重新渲染道具的频率的线索,同时它强制每秒重新渲染父组件两次。
此外,我们有一个 clicks
状态,它告诉我们点击按钮的频率。这就是我们送给孩子们的道具。 因此,如果我们使用 React.memo
,他们应该只在点击次数发生变化时重新渲染
现在请注意,我们有两个不同类型的孩子。一个包裹在 memo
中,一个不是。 Child
未包装,每次父级重新渲染时都会重新渲染。 MemoChild
已包装,只有在点击属性发生变化时才会重新呈现。
const Parent = ( props ) => {
// Ticks is just some state we update 2 times every second to force a parent rerender
const [ticks, setTicks] = React.useState(0);
setTimeout(() => setTicks(ticks + 1), 500);
// The ref allow us to pass down the updated tick without changing the prop (and forcing a rerender)
const tickRef = React.useRef();
tickRef.current = ticks;
// This is the prop children are interested in
const [clicks, setClicks] = React.useState(0);
return (
<div>
<h2>Parent Rendered at tick {tickRef.current} with clicks {clicks}.</h2>
<button
onClick={() => setClicks(clicks + 1)}>
Add extra click
</button>
<Child tickRef={tickRef} clicks={clicks}/>
<MemoChild tickRef={tickRef} clicks={clicks}/>
</div>
);
};
const Child = ({ tickRef, clicks }) => (
<p>Child Rendered at tick {tickRef.current} with clicks {clicks}.</p>
);
const MemoChild = React.memo(Child);
现场示例(也在 CodePen 上):
console.log("HI");
const Parent = ( props ) => {
const [ticks, setTicks] = React.useState(0);
const tickRef = React.useRef();
tickRef.current = ticks;
const [clicks, setClicks] = React.useState(0);
setTimeout(() => setTicks(ticks + 1), 500);
return (
<div>
<h2>Parent Rendered at tick {tickRef.current} with clicks {clicks}.</h2>
<button
onClick={() => setClicks(clicks + 1)}>
Add extra click
</button>
<Child tickRef={tickRef} clicks={clicks}/>
<MemoChild tickRef={tickRef} clicks={clicks}/>
</div>
);
};
const Child = ({ tickRef, clicks }) => (
<p>Child Rendered at tick {tickRef.current} with clicks {clicks}.</p>
);
const MemoChild = React.memo(Child);
ReactDOM.render(
<Parent />,
document.getElementById('root')
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
原文由 the_cheff 发布,翻译遵循 CC BY-SA 4.0 许可协议
在 React 中,功能组件是无状态的,它们没有生命周期方法。 无状态组件是编写 React 组件的一种优雅方式,在我们的包中不需要太多代码。 但是在内部,无状态组件被包装在一个类中,当前没有应用任何优化。这意味着无状态和有状态组件在内部具有相同的代码路径(尽管我们对它们的定义不同)。
但在未来 React 可能会优化无状态组件,如下所述:
shouldComponentUpdate
这是我们可以应用我们的自定义优化并避免不必要的重新渲染组件的地方。该方法与不同类型的组件的用法说明如下:
如前所述,无状态组件没有生命周期方法,因此我们无法使用
shouldComponentUpdate
优化它们。但是它们已经以不同的方式进行了优化,它们具有更简单和优雅的代码结构,并且比具有所有生命周期钩子的组件花费更少的字节。从 React v15.3.0 开始,我们有一个名为
PureComponent
PureRenderMixin
扩展。在引擎盖下,这采用了shouldComponentUpdate
中当前道具/状态与下一个道具/状态的浅比较。也就是说,我们仍然不能依赖
PureComponent
类将我们的组件优化到我们想要的水平。如果我们有Object
类型(数组、日期、普通对象)的道具,就会发生这种异常情况。这是因为我们在比较对象时遇到了这个问题:因此,肤浅的比较不足以确定事情是否发生了变化。但是,如果您的道具只是字符串、数字、布尔值……而不是对象,请使用
PureComponent
类。如果您不想实现自己的自定义优化,也可以使用它。考虑上面的例子;如果我们知道如果
id
发生了变化,那么我们可以通过比较obj1.id === obj2.id
来实现我们自己的自定义优化。那就是我们可以extend
我们正常的Component
基类并使用shouldComponentUpdate
自己做特定键的比较。