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

React中优化多选框选择逻辑、降低循环开销的方案咨询

React购物车多选功能性能优化方案(仿Shopee)

针对你当前实现中存在的循环开销、重复计算问题,结合Shopee购物车这类海量条目场景的最佳实践,给出以下优化方案:


1. 重构数据结构:用Set替代数组存储选中项

原代码用数组存储选中项,includes/indexOf/length判断都是O(n)时间复杂度,改用Set后,所有增删查操作都是O(1),直接解决核心性能瓶颈。

优化后的状态初始化与操作:

import React, { useState, useMemo } from 'react';

const App = () => {
  const lists = [
    { name: 'list1', items: ['a', 'b', 'c'] },
    { name: 'list2', items: ['x', 'y', 'z'] },
    { name: 'list3', items: ['1', '2', '3'] },
  ];

  // 用Set存储每个列表的选中项
  const [selectedLists, setSelectedLists] = useState(() => {
    const initial = {};
    lists.forEach(list => {
      initial[list.name] = new Set();
    });
    return initial;
  });

  // 单个条目选择逻辑
  const handleListItemCheckboxChange = (listName, item) => {
    setSelectedLists(prev => {
      const newSet = new Set(prev[listName]);
      newSet.has(item) ? newSet.delete(item) : newSet.add(item);
      return { ...prev, [listName]: newSet };
    });
  };

2. 用useMemo缓存计算结果,避免重复循环

原代码中allItemsSelected/allListsSelected每次渲染都会遍历列表,用useMemo缓存这些计算结果,仅当依赖项变化时才重新计算。

缓存全选状态:

// 预构建列表名称到列表的映射(避免重复find)
const listMap = useMemo(() => {
  return lists.reduce((acc, list) => {
    acc[list.name] = list;
    return acc;
  }, {});
}, [lists]);

// 缓存每个列表的全选状态
const listSelectionStatus = useMemo(() => {
  return lists.reduce((acc, list) => {
    acc[list.name] = selectedLists[list.name].size === list.items.length;
    return acc;
  }, {});
}, [lists, selectedLists]);

// 缓存整体全选状态
const isAllListsSelected = useMemo(() => {
  return lists.every(list => listSelectionStatus[list.name]);
}, [lists, listSelectionStatus]);

3. 组件拆分+React.memo,减少不必要重渲染

将列表项、列表容器拆分为独立组件,用React.memo包裹,仅当props变化时才重渲染,避免父组件更新时所有子组件全量刷新。

拆分后的子组件:

// 列表项组件
const ListItem = React.memo(({ item, isChecked, onChange }) => {
  return (
    <div>
      <input
        type="checkbox"
        checked={isChecked}
        onChange={onChange}
      />
      {item}
    </div>
  );
});

// 列表容器组件
const ListSection = React.memo(({ list, selectedSet, onListToggle, onItemToggle }) => {
  const isListSelected = selectedSet.size === list.items.length;
  return (
    <div>
      <button onClick={() => onListToggle(list.name, list.items)}>
        {isListSelected ? `Unselect ${list.name}` : `Select ${list.name}`}
      </button>
      {list.items.map(item => (
        <ListItem
          key={item}
          item={item}
          isChecked={selectedSet.has(item)}
          onChange={() => onItemToggle(list.name, item)}
        />
      ))}
    </div>
  );
});

父组件中调用:

return (
  <div>
    <button onClick={handleAllListsCheckboxChange}>
      {isAllListsSelected ? 'Unselect All' : 'Select All'}
    </button>
    {lists.map(list => (
      <ListSection
        key={list.name}
        list={list}
        selectedSet={selectedLists[list.name]}
        onListToggle={handleListCheckboxChange}
        onItemToggle={handleListItemCheckboxChange}
      />
    ))}
  </div>
);

4. 优化全选/反选逻辑,合并循环操作

原代码中全选逻辑分两次遍历列表,优化后合并为一次遍历,减少循环次数:

const handleAllListsCheckboxChange = () => {
  setSelectedLists(prev => {
    const newState = {};
    const shouldSelectAll = !isAllListsSelected;
    lists.forEach(list => {
      newState[list.name] = shouldSelectAll ? new Set(list.items) : new Set();
    });
    return newState;
  });
};

const handleListCheckboxChange = (listName, listItems) => {
  setSelectedLists(prev => {
    const currentSet = prev[listName];
    const newSet = currentSet.size === listItems.length 
      ? new Set() 
      : new Set(listItems);
    return { ...prev, [listName]: newSet };
  });
};

最终优化后的完整代码

整合以上所有优化点,最终代码的性能在海量条目场景下会有显著提升:

import React, { useState, useMemo } from 'react';

// 列表项组件
const ListItem = React.memo(({ item, isChecked, onChange }) => {
  return (
    <div>
      <input
        type="checkbox"
        checked={isChecked}
        onChange={onChange}
      />
      {item}
    </div>
  );
});

// 列表容器组件
const ListSection = React.memo(({ list, selectedSet, onListToggle, onItemToggle }) => {
  const isListSelected = selectedSet.size === list.items.length;
  return (
    <div>
      <button onClick={() => onListToggle(list.name, list.items)}>
        {isListSelected ? `Unselect ${list.name}` : `Select ${list.name}`}
      </button>
      {list.items.map(item => (
        <ListItem
          key={item}
          item={item}
          isChecked={selectedSet.has(item)}
          onChange={() => onItemToggle(list.name, item)}
        />
      ))}
    </div>
  );
});

const App = () => {
  const lists = [
    { name: 'list1', items: ['a', 'b', 'c'] },
    { name: 'list2', items: ['x', 'y', 'z'] },
    { name: 'list3', items: ['1', '2', '3'] },
  ];

  // 用Set存储每个列表的选中项
  const [selectedLists, setSelectedLists] = useState(() => {
    const initial = {};
    lists.forEach(list => {
      initial[list.name] = new Set();
    });
    return initial;
  });

  // 预构建列表名称到列表的映射
  const listMap = useMemo(() => {
    return lists.reduce((acc, list) => {
      acc[list.name] = list;
      return acc;
    }, {});
  }, [lists]);

  // 缓存每个列表的全选状态
  const listSelectionStatus = useMemo(() => {
    return lists.reduce((acc, list) => {
      acc[list.name] = selectedLists[list.name].size === list.items.length;
      return acc;
    }, {});
  }, [lists, selectedLists]);

  // 缓存整体全选状态
  const isAllListsSelected = useMemo(() => {
    return lists.every(list => listSelectionStatus[list.name]);
  }, [lists, listSelectionStatus]);

  // 单个条目选择逻辑
  const handleListItemCheckboxChange = (listName, item) => {
    setSelectedLists(prev => {
      const newSet = new Set(prev[listName]);
      newSet.has(item) ? newSet.delete(item) : newSet.add(item);
      return { ...prev, [listName]: newSet };
    });
  };

  // 单个列表全选/反选逻辑
  const handleListCheckboxChange = (listName, listItems) => {
    setSelectedLists(prev => {
      const currentSet = prev[listName];
      const newSet = currentSet.size === listItems.length 
        ? new Set() 
        : new Set(listItems);
      return { ...prev, [listName]: newSet };
    });
  };

  // 所有列表全选/反选逻辑
  const handleAllListsCheckboxChange = () => {
    setSelectedLists(prev => {
      const newState = {};
      const shouldSelectAll = !isAllListsSelected;
      lists.forEach(list => {
        newState[list.name] = shouldSelectAll ? new Set(list.items) : new Set();
      });
      return newState;
    });
  };

  return (
    <div>
      <button onClick={handleAllListsCheckboxChange}>
        {isAllListsSelected ? 'Unselect All' : 'Select All'}
      </button>
      {lists.map(list => (
        <ListSection
          key={list.name}
          list={list}
          selectedSet={selectedLists[list.name]}
          onListToggle={handleListCheckboxChange}
          onItemToggle={handleListItemCheckboxChange}
        />
      ))}
    </div>
  );
};

export default App;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 06:25:12