对这个知识点的深入是从下面这篇文章的一个小疑问开始的: 如果不使用useMemo,我们应该怎么办?
如果不使用useMemo,我们应该怎么办
下面ExpensiveTree
是一个渲染极其昂贵的组件,状态color的变化会导致App
的重渲染,从而导致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>;
}
那有什么办法避免呢
状态下移
将变化的部分与不变化的部分分开,此时状态color
从App
组件下移到Form
组件中,则color
的变化只会导致Form
组件的re-render。
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>
</>
);
}
内容提升
如果是最外层的div
需要状态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>
);
}
此时就要去了解parent
和owner
这两个概念的区别了
有两种原因会导致组件的re-render:
- self-update: 自身state的变化,会导致自身的re-render
- owner-update:默认来说,当一个组件re-render,会导致其own的所有组件re-render。
parent和owner的区别:
- Parent: the component or
element
in which the other component is nested. - Owner: the component which renders the other component.
如下代码所示,App
是ExpensiveTree
的owner component
,ColorPicker
是ExpensiveTree
的parent component
。故由于ExpensiveTree
的owner是App
,故ColorPicker
的re-render不会导致ExpensiveTree
的re-render。
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>
);
}