问题描述
在如下代码的情况下,如果我们点击按钮,会发现即使A
和B
组件没有依赖timestamp
,但每次setTimestamp
也会让函数重新渲染,这其实是无意义的性能开销。
function A() {
console.log('render A');
return <>A</>;
}
function B() {
console.log('render B');
return <>B</>;
}
function App() {
const [timestamp, setTimestamp] = useState(0);
const onClick = () => {
setTimestamp(Date.now());
};
console.log('render App');
return (
<>
<button onClick={onClick}>setTimestamp</button>
<A />
<B />
</>
);
}
// 每次调用setTimestamp,都会输出
// render App
// render A
// render B
分析问题
那为什么会发生这种无意义的渲染呢?
其本质是react
无法判断你当前更新的timestamp
,是否跟子组件A
和B
有某种内在联系(即使你明确的知道子组件没用使用它)。
所以react
会假定所有的子组件都需要重新渲染,也就会导致了本文中的无意义的性能开销。
解决问题
方案1:使用React.memo
包裹子组件。
当组件的props
没有发生改变时,React.memo
能够让组件会跳过渲染,规避了上面的问题。
const A = React.memo(function () {
console.log('render A');
return <>A</>;
});
const B = React.memo(function () {
console.log('render B');
return <>B</>;
});
function App() {
const [timestamp, setTimestamp] = useState(0);
const onClick = () => {
setTimestamp(Date.now());
};
console.log('render App');
return (
<>
<button onClick={onClick}>setTimestamp</button>
<A />
<B />
</>
);
}
// 每次调用setTimestamp,只会输出
// render App
方案2:将timestamp
封装到独立的组件中。
这样重新渲染的范围就被限定到了Time
的组件中,而不会导致其他外部组件的重新渲染。
function A() {
console.log('render A');
return <>A</>;
}
function B() {
console.log('render B');
return <>B</>;
}
function Time() {
const [timestamp, setTimestamp] = useState(0);
const onClick = () => {
setTimestamp(Date.now());
};
console.log('render Time');
return (
<>
<button onClick={onClick}>setTimestamp</button>
</>
);
}
function App() {
console.log('render App');
return (
<>
<Time />
<A />
<B />
</>
);
}
// 每次调用setTimestamp,只会输出
// render Time
总结问题
暂无
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。