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
相关产品推荐
相关产品推荐

