我想弄清楚为什么当我点击一个特定的组件时,它的兄弟组件也会渲染
function CountButton({increment, count, number}) {
console.log(`Render CountButton ${number}`)
return <button onClick={() => increment(count + 1)}>{count}</button>
}
function DualCounter() {
const [count1, setCount1] = React.useState(0)
const increment1 = React.useCallback(() => setCount1(c => c + 1), [])
const [count2, setCount2] = React.useState(0)
const increment2 = React.useCallback(() => setCount2(c => c + 1), [])
console.log('Render DualCounter')
return (
<>
<CountButton count={count1} increment={increment1} number={1} />
<CountButton count={count2} increment={increment2} number={2} />
</>
)
}
我使用 useCallback
并传递这些函数以避免在任何渲染中函数引用将是不同的引用。
答案 0 :(得分:3)
您在兄弟组件 <CountButton />
上看到了重新渲染,因为每次点击按钮更新计数器时,您实际上是在更新父组件 <DualCounter />
中的状态值,即也会导致在该组件上重新渲染。
并且由于 DualCounter
被重新渲染,子组件也将重新渲染,在这种情况下包括 <CountButton />
元素。
防止这种情况的解决方案是使用 React.memo() 包装 CountButton 组件。这将防止对 props 值没有任何更改的组件进行重新渲染。
示例如下:
function CountButton({increment, count, number}) {
console.log(`Render CountButton ${number}`)
return <button onClick={() => increment(count + 1)}>{count}</button>
}
const CountButtonMemo = React.memo(CountButton)
function DualCounter() {
const [count1, setCount1] = React.useState(0)
const increment1 = React.useCallback(() => setCount1(c => c + 1), [])
const [count2, setCount2] = React.useState(0)
const increment2 = React.useCallback(() => setCount2(c => c + 1), [])
console.log('Render DualCounter')
return (
<>
<CountButtonMemo count={count1} increment={increment1} number={1} />
<CountButtonMemo count={count2} increment={increment2} number={2} />
</>
)
另一种解决方案是不对由 DualCounter
组件上的事件引起的每次更改更新 CountButton
状态,这将停止在其兄弟组件上触发不需要的重新渲染。如果这对您的应用有意义,您可以直接在每个 CountButton 组件上处理状态。
或者,您可以使用 React 状态管理工具,例如 Redux,它也可以解决这个问题,负责将应用的状态与组件本身分离。