我们一般做React性能优化,有两条思路
1、验证是否将树中的状态放在了一个比实际所需更高的位置上。(例如,将输入框的state放到了集中的store里,这样并不合理)
2、运行React开发者工具来检测是什么导致了二次渲染,以及在高开销的子树上包裹memo()。(以及在需要的地方使用useMemo())
除了上面两条思路外,分享两个基础的小技巧😊来提升渲染性能:
这里是一个具有严重渲染性能问题的组件(当App中的color变化时,我们会重新渲染一次被<ExpensiveTree />组件)
import { useState } from 'react';
export default function App() {
let [color, setColor] = useState('red');
return (
<div>
<input value={color} onChange={(e) => setColor(e.target.value)} />
<p style={{ color }}>Hello, world!</p>
<ExpensiveTree />
</div>
);
}
function ExpensiveTree() {
let now = performance.now();
while (performance.now() - now < 100) {
// Artificial delay -- do nothing for 100ms
}
return <p>I am a very slow component tree.</p>;
}
用我们常用的思路给ExpensiveTree上价格memo()就可以解决此问题。
接下来就说说我们的技巧吧。
技巧1: 向下移动State
仔细看一下渲染代码,可以注意到返回的树中只有一部分真正关心当前的color
所以让我们把这一部分提取到Form组件中然后将state移动到该组件里:
export default function App() {
return (
<>
<Form />
<ExpensiveTree />
</>
);
}
function Form() {
let [color, setColor] = useState('red');
return (
<>
<input value={color} onChange={(e) => setColor(e.target.value)} />
<p style={{ color }}>Hello, world!</p>
</>
);
}
现在如果color变化了,只有Form会重新渲染,问题解决了。
技巧 2:内容提升
当一部分state在高开销树的上层代码中使用时上述解法就无法奏效了。比吐将color放到父元素div中使用(<div style={{ color }}>)。
export default function App() {
let [color, setColor] = useState('red');
return (
<div style={{ color }}>
<input value={color} onChange={(e) => setColor(e.target.value)} />
<p>Hello, world!</p>
<ExpensiveTree />
</div>
);
}
没办法将不使用color的部分提取到另一个组件中了,因为color要在ExpensiveTree的父组件div中使用。
我们可以将App组件分割为两个子组件。依赖color的代码就和color state变量一起放入ColorPicker组件里。 不关心color的部分就依然放在App组件中,然后以JSX内容的形式传递给ColorPicker,也被称为children属性。 当color变化时,ColorPicker会重新渲染。但是它仍然保存着上一次从App中拿到的相同的children属性,所以React并不会访问那棵子树。 因此,ExpensiveTree不会重新渲染。
export default function App() {
return (
<ColorPicker>
<p>Hello, world!</p>
<ExpensiveTree />
</ColorPicker>
);
}
function ColorPicker({ children }) {
let [color, setColor] = useState("red");
return (
<div style={{ color }}>
<input value={color} onChange={(e) => setColor(e.target.value)} />
{children}
</div>
);
}
这两种技巧和memo是互补的,可以根据实际场景来决定使用哪种方式提升渲染性能。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。