如何避免 React 中不必要的重新渲染?
How to avoid unnecessary re-renders in React?
我知道这个问题已经被问过很多次了,但我想了解当状态发生变化时反应渲染决策背后的逻辑以及我应该如何正确地写“反应”。
这是我的代码:
// Parent.js
import React, { useEffect, useState } from "react";
import ComponentA from "./ComponentA";
import ComponentB from "./ComponentB";
export default function App() {
const [a, setA] = useState(false);
const [b, setB] = useState(false);
const onClickA = () => {
setA((p) => !p);
};
const onClickB = () => {
setB((p) => !p);
};
useEffect(() => {
console.log("Parent rendered");
});
return (
<div>
<ComponentA value={a} onClick={onClickA} />
<ComponentB value={b} onClick={onClickB} />
</div>
);
}
// Child A
import React, { useEffect } from "react";
export default function ComponentA(props) {
useEffect(() => {
console.log("A rendered");
});
return (
<button onClick={props.onClick}>Button A - {props.value.toString()}</button>
);
}
// Child B
import React, { useEffect } from "react";
export default function ComponentB(props) {
useEffect(() => {
console.log("B rendered");
});
return (
<button onClick={props.onClick}>Button B - {props.value.toString()}</button>
);
}
因此,当我单击按钮 A 或按钮 B 时,父组件将重新呈现,导致 ComponentA 和 ComponentB 重新呈现,即使每个 UI 与另一个的状态无关。我在想反应会明白如果我点击按钮A,只有a
状态变量改变了,而<ComponentB />
不依赖于a
状态所以不需要重新再次渲染它,因为它的 props
保持不变。所以我认为这段代码是错误的,应该用不同的风格来写,但我想不通。
很明显,我想既然a
不影响<ComponentB />
,b
也不影响<ComponentA />
,那我干脆把状态传给每个组件分别?这样,每个组件都将负责自己的重新渲染。但是转念一想,万一以后 ComponentA
依赖于 b
或者 ComponentB
依赖于 a
呢?每次我想分享状态时,我都无法更改代码,编写回调函数并将状态转换为道具,反之亦然。
有没有更好的方法可以提供这种灵活性而无需太多开销代码(ex redux)?
这就是 React 的关键概念。如果组件重新渲染,默认情况下所有子组件都将重新渲染。这不是问题,因为它通常非常快 - 除非您在渲染函数中进行昂贵的计算,而您不应该这样做。
有一些逃生通道,例如 React.memo
和 shouldComponentUpdate
class 生命周期函数,但通常您不需要它们,过早的优化往往弊大于利。
如果您遇到性能问题,请对其进行测量,然后优化您发现的问题。否则,不要过多地重新渲染。
我知道这个问题已经被问过很多次了,但我想了解当状态发生变化时反应渲染决策背后的逻辑以及我应该如何正确地写“反应”。
这是我的代码:
// Parent.js
import React, { useEffect, useState } from "react";
import ComponentA from "./ComponentA";
import ComponentB from "./ComponentB";
export default function App() {
const [a, setA] = useState(false);
const [b, setB] = useState(false);
const onClickA = () => {
setA((p) => !p);
};
const onClickB = () => {
setB((p) => !p);
};
useEffect(() => {
console.log("Parent rendered");
});
return (
<div>
<ComponentA value={a} onClick={onClickA} />
<ComponentB value={b} onClick={onClickB} />
</div>
);
}
// Child A
import React, { useEffect } from "react";
export default function ComponentA(props) {
useEffect(() => {
console.log("A rendered");
});
return (
<button onClick={props.onClick}>Button A - {props.value.toString()}</button>
);
}
// Child B
import React, { useEffect } from "react";
export default function ComponentB(props) {
useEffect(() => {
console.log("B rendered");
});
return (
<button onClick={props.onClick}>Button B - {props.value.toString()}</button>
);
}
因此,当我单击按钮 A 或按钮 B 时,父组件将重新呈现,导致 ComponentA 和 ComponentB 重新呈现,即使每个 UI 与另一个的状态无关。我在想反应会明白如果我点击按钮A,只有a
状态变量改变了,而<ComponentB />
不依赖于a
状态所以不需要重新再次渲染它,因为它的 props
保持不变。所以我认为这段代码是错误的,应该用不同的风格来写,但我想不通。
很明显,我想既然a
不影响<ComponentB />
,b
也不影响<ComponentA />
,那我干脆把状态传给每个组件分别?这样,每个组件都将负责自己的重新渲染。但是转念一想,万一以后 ComponentA
依赖于 b
或者 ComponentB
依赖于 a
呢?每次我想分享状态时,我都无法更改代码,编写回调函数并将状态转换为道具,反之亦然。
有没有更好的方法可以提供这种灵活性而无需太多开销代码(ex redux)?
这就是 React 的关键概念。如果组件重新渲染,默认情况下所有子组件都将重新渲染。这不是问题,因为它通常非常快 - 除非您在渲染函数中进行昂贵的计算,而您不应该这样做。
有一些逃生通道,例如 React.memo
和 shouldComponentUpdate
class 生命周期函数,但通常您不需要它们,过早的优化往往弊大于利。
如果您遇到性能问题,请对其进行测量,然后优化您发现的问题。否则,不要过多地重新渲染。