You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React组件优化:如何控制兄弟组件的重渲染?

解决方案:优化重渲染并修复勾选状态丢失问题

核心问题分析

  1. 状态更新逻辑错误:直接用[...wandsChecked, veh]更新状态,既没处理取消勾选的场景,还因闭包问题导致useCallback里的wandsChecked始终是初始空数组,每次点击只会保留当前魔杖,之前的勾选丢失,看起来像是被取消。
  2. 不必要的重渲染:父组件Wands状态更新时,所有Wand子组件都会跟着重渲染,未做渲染优化。
  3. 复选框状态绑定错误:用value属性控制勾选状态不符合React规范,应该用checked属性。

分步解决

1. 修复状态更新逻辑(支持选中/取消)

使用setWandsChecked的函数式更新规避闭包问题,同时判断当前魔杖是否已在勾选列表中,实现添加/移除的双向逻辑:

const toggleWandChecked = useCallback((wand) => {
  setWandsChecked(prev => {
    // 判断是否已勾选,已勾选则移除,否则添加
    return prev.some(item => item.name === wand.name)
      ? prev.filter(item => item.name !== wand.name)
      : [...prev, wand];
  });
}, []);

2. 用React.memo包裹Wand组件

React.memo会对比组件的props,只有当props变化时才触发重渲染。因为toggleWandChecked用useCallback包裹且依赖为空,wand属性稳定,所以只有当前点击的Wand组件会重渲染(更新自身勾选状态),其他组件不会。

3. 正确绑定复选框的checked状态

根据当前魔杖是否在wandsChecked列表中,直接设置checked属性:

<input 
  type="checkbox" 
  id={wand.name} 
  checked={wandsChecked.some(item => item.name === wand.name)}
  onClick={() => toggleWandChecked(wand)}
/>

修改后的完整代码

import { useState, useCallback, memo } from 'react';
import WandsChecked from './WandsChecked';

function Wands ({wands}) {
  console.log('Wands re-rendering');
  const [wandsChecked, setWandsChecked] = useState([]);

  // 优化后的状态更新函数,支持选中/取消,避免闭包问题
  const toggleWandChecked = useCallback((wand) => {
    setWandsChecked(prev => {
      const isChecked = prev.some(item => item.name === wand.name);
      return isChecked
        ? prev.filter(item => item.name !== wand.name)
        : [...prev, wand];
    });
  }, []);

  return (
    <main>
      <div className='grid gap-4 grid-cols-3 grid-rows-3'>
        {wands?.map(wand => (
          <Wand 
            key={wand.name} // 必须添加唯一key,避免React渲染混乱
            wand={wand} 
            isChecked={wandsChecked.some(item => item.name === wand.name)}
            onToggle={toggleWandChecked} 
          />
        ))}
      </div>
      <div className='grid gap-4 grid-cols-3 grid-rows-3'>
        <WandsChecked WandsToCompare={wandsChecked}/>
      </div>
    </main>
  )
}

// 用memo包裹,避免不必要的重渲染
const Wand = memo(({ wand, isChecked, onToggle }) => {
  console.log(`Wand ${wand.name} re-rendering`);

  return (
    <div className='wand-wrapper basis-1/4'>
      <div className='wand-banner'>
        <input 
          type="checkbox" 
          id={wand.name} 
          checked={isChecked}
          onClick={() => onToggle(wand)}
        />
        <label htmlFor={wand.name}>{wand.name}</label>
      </div>
    </div>
  )
});

export default Wands;

额外优化点

  • 添加了key属性:遍历渲染组件时必须添加唯一key,帮助React识别组件身份,优化渲染性能。
  • 将isChecked状态直接传递给Wand组件,避免子组件重复计算,简化逻辑。
  • 移除了不必要的async,状态更新是同步操作,无需异步函数。

内容的提问来源于stack exchange,提问作者QuietCoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 11:05:16