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

React中追踪对象数组属性变化的最佳实现方法

动态数组对象属性变化追踪方案

需求背景

我们有一个存储在React状态中的CheckItem类型对象数组(长度不固定),需要控制“Apply Changes”按钮的禁用状态:

  • 按钮默认保持禁用,直到数组中任意对象的任意属性被修改
  • 若用户撤销所有修改,按钮需恢复禁用状态

最优实现思路

兼顾空间与时间效率的核心是保存原始状态快照+高效差异比较:

  1. 用useRef存储初始状态的深拷贝快照,避免引用类型污染,确保原始状态不受后续修改影响
  2. 实现轻量差异比较逻辑,仅在当前状态或原始快照变化时重新计算差异,避免不必要的重复计算
  3. 根据比较结果动态设置按钮的禁用状态

完整代码示例

import { useState, useEffect, useRef, useMemo } from 'react';

interface CheckItem {
  label: string;
  checked: boolean;
  disabled: boolean;
}

const CheckboxGroup = () => {
  const [checkboxes, setCheckboxes] = useState<CheckItem[] | undefined>(undefined);
  // 存储原始状态快照的ref
  const originalCheckboxesRef = useRef<CheckItem[] | undefined>(undefined);

  const checkboxArr: CheckItem[] = [
    { label: 'item1', checked: true, disabled: false },
    { label: 'item2', checked: false, disabled: false }
  ];

  // 初始化状态并保存原始快照
  useEffect(() => {
    const initialData = JSON.parse(JSON.stringify(checkboxArr));
    setCheckboxes(initialData);
    originalCheckboxesRef.current = initialData;
  }, []);

  // 处理单个复选框属性修改的示例函数
  const handleCheckboxChange = (index: number, key: keyof CheckItem, value: any) => {
    if (!checkboxes) return;
    setCheckboxes(prev => {
      const newArr = [...prev];
      newArr[index] = { ...newArr[index], [key]: value };
      return newArr;
    });
  };

  // 高效计算是否有修改发生
  const hasChanges = useMemo(() => {
    if (!checkboxes || !originalCheckboxesRef.current) return false;
    // 先比较数组长度,快速判断差异
    if (checkboxes.length !== originalCheckboxesRef.current.length) return true;
    // 逐个比较每个对象的所有属性
    return !checkboxes.every((item, index) => {
      const originalItem = originalCheckboxesRef.current![index];
      return item.label === originalItem.label &&
             item.checked === originalItem.checked &&
             item.disabled === originalItem.disabled;
    });
  }, [checkboxes]);

  return (
    <div>
      {checkboxes?.map((item, index) => (
        <div key={index}>
          <input
            type="checkbox"
            checked={item.checked}
            disabled={item.disabled}
            onChange={(e) => handleCheckboxChange(index, 'checked', e.target.checked)}
          />
          <input
            type="text"
            value={item.label}
            onChange={(e) => handleCheckboxChange(index, 'label', e.target.value)}
          />
          <input
            type="checkbox"
            checked={item.disabled}
            onChange={(e) => handleCheckboxChange(index, 'disabled', e.target.checked)}
            label="Disable this item"
          />
        </div>
      ))}
      <button disabled={!hasChanges}>Apply Changes</button>
    </div>
  );
};

export default CheckboxGroup;

方案说明

  • 快照存储:使用JSON.parse(JSON.stringify())做深拷贝,对于结构简单的对象足够高效;如果对象包含复杂类型(如Date、函数),可以改用递归深拷贝或专用工具函数
  • 差异比较:先比较数组长度快速筛选差异,再逐个对象比对属性,这种方式比全量深比较更高效,一旦发现差异就提前返回结果
  • 性能优化:用useMemo缓存比较结果,仅当checkboxes状态变化时重新计算,避免每次渲染都执行比较逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 11:31:03