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

React setState数组Hook无法触发组件重渲染问题排查

React折叠表格不触发重渲染的问题解决

你遇到的核心问题是直接修改了React state的原引用,React依赖state的引用变化来触发重渲染,当你直接修改原数组/对象时,React检测不到变化,所以不会更新视图。

代码里的具体问题

  1. 直接复用state引用:let temp = dataShow; 这行只是把原state数组的引用赋值给temp,后续对temp的修改其实就是在修改原state,React认为数组引用没变化,不会触发重渲染。
  2. 可变操作修改对象:不管是delete temp[idx].var还是temp[idx]['var'] = [],都是直接修改原state里的对象,没有创建新的对象/数组副本,React无法感知到变化。
  3. map参数顺序错误:row.var.map((var_idx, var_value) => 这里参数顺序搞反了,map的第一个参数是数组元素,第二个是索引,会导致key生成错误,影响渲染。

修复后的代码

JavaScript部分

const data = {
  'T-Shirt Minion': {
    'total': 571,
    'var': {
      'Lengan Panjang': {
        'total': 431,
        'colour': {
          'Merah': {
            'total': 431,
            'size': {
              'XL': 231,
              'S': 100,
              'M': 100
            }
          }
        }
      },
      'Lengan Pendek': {
        'total': 140,
        'colour': {
          'Merah': {
            'total': 140,
            'size': {
              'L': 140
            }
          }
        }
      }
    }
  }
};

function MyApp() {
  const [dataShow, setDataShow] = React.useState([]);

  React.useEffect(() => {
    // 初始化时用不可变方式生成初始数据
    const initialData = Object.keys(data).map(key => ({
      name: key,
      total: data[key].total
    }));
    setDataShow(initialData);
  }, []);

  const handleNameClick = (idx, name) => {
    setDataShow(prev => {
      // 创建原数组的副本,避免修改原state引用
      const newDataShow = [...prev];
      // 复制要修改的行,生成新对象
      const targetRow = {...newDataShow[idx]};

      if (targetRow.var) {
        // 折叠:删除var属性,返回新对象
        delete targetRow.var;
      } else {
        // 展开:从原数据中提取var数据并转为数组
        const varData = data[name]['var'];
        targetRow.var = Object.keys(varData).map(key => ({
          name: key,
          total: varData[key].total
        }));
      }

      // 替换副本中的目标行
      newDataShow[idx] = targetRow;
      return newDataShow;
    });
  };

  return ( 
  <table border="1">
                    <thead>
                        <tr>
                            <th> </th>
                            <th>Name</th>
                            <th>Variant</th>
                            <th>Colour</th>
                            <th>Size</th>
                            <th>Stock</th>
                        </tr>
                    </thead>
                    <tbody>
                      {dataShow.map((row, index) => (
                        <React.Fragment key={`${index}-${row.name}`}>
                            <tr>
                                <td style={{ cursor: "pointer" }} 
                                    onClick={() => handleNameClick(index, row.name)}>
                                    {/* 动态切换展开/折叠按钮文本 */}
                                    {row.var ? '-' : '+'}
                                </td>
                                <td colSpan={4} >{row.name}</td>
                                <td>{row.total}</td>
                            </tr>
                            {row.var ? row.var.map((var_value, var_idx) => (
                                <React.Fragment key={`${index}-${var_idx}-${var_value.name}`}>
                                    <tr>
                                        <td style={{ cursor: "pointer" }}> + </td>
                                        <td> </td>
                                        <td colSpan={3}>{var_value.name}</td>
                                        <td>{var_value.total}</td>
                                    </tr>
                                </React.Fragment>
                            )) : null }
                        </React.Fragment>
                      ))}
                    </tbody>
                </table>
  );
}

ReactDOM.render( <
  MyApp / > ,
  document.getElementById('root')
);

HTML部分

<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>

<div id="root"></div>

修复要点说明

  • 所有state更新都基于prev state创建新的数组/对象副本,保证引用变化,触发React重渲染。
  • 初始化state时用map一次性生成数组,避免多次调用setDataShow。
  • 修正了map的参数顺序,同时优化了key的生成规则,避免重复冲突。
  • 新增展开/折叠按钮的文本切换逻辑,提升交互体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 07:54:22