如何避免在 React 中不必要地重新渲染组件?
How to avoid unnecessary re-render of a component in React?
我有这个案例:
const Parent = () => {
const [value, setValue] = useState('');
return <>
<Child1 value={value} />
<Child2 setValue={setValue} />
</>
}
但是每次调用 Child2
的 setValue
时,Child2
都会重新渲染,尽管它的道具没有改变(Child1 也会重新渲染,但这是预期的自道具 value
更改后的行为)。
如何解决这个问题?
这就是React.memo or useMemo的目的。
示例
const Parent = () => {
const [value, setValue] = useState('');
const child2 = useMemo(() => <Child2 setValue={setValue} />, [setValue])
return <>
<Child1 value={value} />
{child2}
</>
}
[setValue]
是依赖数组。更改此数组中的任何内容都会导致重新计算该值。
它重新渲染的原因,即使道具没有改变,是因为你正在改变父组件的状态。这会导致 Parent 组件重新渲染,这将重新渲染所有子组件,无论它们的 props 是否改变。
或者,您可以像这样在子组件上使用 React.memo:
const Child2 = React.memo(function Child2(props) {
/* ... */
});
React useState
状态更新函数保证是稳定的引用,所以 Child2
只是重新渲染,因为父组件 Parent
由于状态更新而重新渲染。如果您想向 React 暗示它可能会放弃重新渲染子组件,请使用 memo 高阶组件。
const Child2 = ({ setValue }) => {
....
};
export default memo(Child2);
演示
演示 Child 2 的 2 个“实例”,一个用 memo
HOC 装饰,另一个没有。所有子项在呈现时都使用 useEffect
进行记录。请注意,所有初始渲染,但只有子 1 和 2(w/o 备忘录)不断重新渲染。
沙盒代码:
import { memo, useEffect, useState } from "react";
import "./styles.css";
const Child1 = ({ value }) => {
useEffect(() => console.log("Child 1 rendered"));
return <div>Child1: {value}</div>;
};
const Child2 = ({ id, setValue }) => {
useEffect(() => console.log(`${id} rendered`));
return (
<div>
{id}: <input type="text" onChange={(e) => setValue(e.target.value)} />
</div>
);
};
const Child2wMemo = memo(Child2);
const Parent = () => {
const [value, setValue] = useState("");
return (
<>
<Child1 value={value} />
<Child2 id="Child 2" setValue={setValue} />
<Child2wMemo id="Child 2 with Memo" setValue={setValue} />
</>
);
};
export default function App() {
return (
<div className="App">
<Parent />
</div>
);
}
我有这个案例:
const Parent = () => {
const [value, setValue] = useState('');
return <>
<Child1 value={value} />
<Child2 setValue={setValue} />
</>
}
但是每次调用 Child2
的 setValue
时,Child2
都会重新渲染,尽管它的道具没有改变(Child1 也会重新渲染,但这是预期的自道具 value
更改后的行为)。
如何解决这个问题?
这就是React.memo or useMemo的目的。
示例
const Parent = () => {
const [value, setValue] = useState('');
const child2 = useMemo(() => <Child2 setValue={setValue} />, [setValue])
return <>
<Child1 value={value} />
{child2}
</>
}
[setValue]
是依赖数组。更改此数组中的任何内容都会导致重新计算该值。
它重新渲染的原因,即使道具没有改变,是因为你正在改变父组件的状态。这会导致 Parent 组件重新渲染,这将重新渲染所有子组件,无论它们的 props 是否改变。
或者,您可以像这样在子组件上使用 React.memo:
const Child2 = React.memo(function Child2(props) {
/* ... */
});
React useState
状态更新函数保证是稳定的引用,所以 Child2
只是重新渲染,因为父组件 Parent
由于状态更新而重新渲染。如果您想向 React 暗示它可能会放弃重新渲染子组件,请使用 memo 高阶组件。
const Child2 = ({ setValue }) => {
....
};
export default memo(Child2);
演示
演示 Child 2 的 2 个“实例”,一个用 memo
HOC 装饰,另一个没有。所有子项在呈现时都使用 useEffect
进行记录。请注意,所有初始渲染,但只有子 1 和 2(w/o 备忘录)不断重新渲染。
沙盒代码:
import { memo, useEffect, useState } from "react";
import "./styles.css";
const Child1 = ({ value }) => {
useEffect(() => console.log("Child 1 rendered"));
return <div>Child1: {value}</div>;
};
const Child2 = ({ id, setValue }) => {
useEffect(() => console.log(`${id} rendered`));
return (
<div>
{id}: <input type="text" onChange={(e) => setValue(e.target.value)} />
</div>
);
};
const Child2wMemo = memo(Child2);
const Parent = () => {
const [value, setValue] = useState("");
return (
<>
<Child1 value={value} />
<Child2 id="Child 2" setValue={setValue} />
<Child2wMemo id="Child 2 with Memo" setValue={setValue} />
</>
);
};
export default function App() {
return (
<div className="App">
<Parent />
</div>
);
}