如何优化React中的复选框选择逻辑并最小化循环?

问题描述 投票:0回答:1

我正在开发一个 React 项目,其中有多个带有复选框的项目列表,类似于 Shopee 购物车页面中的复选框选择功能。目前,我已经使用 React 状态实现了复选框功能,并处理单个复选框和全选复选框的事件。

但是,我担心性能影响,尤其是在处理大量列表或项目时。我注意到我的代码涉及多个循环,想知道是否有更好的方法来优化选择逻辑并最大限度地减少循环的使用。

这是我的代码的简化版本:

import React, { useState } from 'react';

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

  const [selectedLists, setSelectedLists] = useState(() => {
    const initialSelectedLists = {};
    lists.forEach((list) => {
      initialSelectedLists[list.name] = [];
    });
    return initialSelectedLists;
  });

  const handleListCheckboxChange = (listName, listItems) => {
    const newListState = { ...selectedLists };
    const currentList = newListState[listName];
    newListState[listName] = currentList.length === listItems.length ? [] : [...listItems];
    setSelectedLists(newListState);
  };

  const handleAllListsCheckboxChange = () => {
    const newListState = {};
    const anyListUnselected = lists.some((list) => {
      const { name, items } = list;
      return selectedLists[name].length !== items.length;
    });

    lists.forEach((list) => {
      const { name, items } = list;
      newListState[name] = anyListUnselected ? [...items] : [];
    });

    setSelectedLists(newListState);
  };

  const handleListItemCheckboxChange = (listName, item) => {
    const newListState = { ...selectedLists };
    const currentList = newListState[listName];
    const itemIndex = currentList.indexOf(item);

    if (itemIndex !== -1) {
      newListState[listName] = [
        ...currentList.slice(0, itemIndex),
        ...currentList.slice(itemIndex + 1),
      ];
    } else {
      newListState[listName] = [...currentList, item];
    }

    setSelectedLists(newListState);
  };

  const allItemsSelected = (listName) => {
    const list = getListByName(listName);
    return selectedLists[listName].length === list.items.length;
  };

  const allListsSelected = () => {
    return lists.every((list) =>
      allItemsSelected(list.name)
    );
  };

  const getListByName = (listName) => {
    return lists.find((list) => list.name === listName);
  };

  return (
    <div>
      <button onClick={handleAllListsCheckboxChange}>
        {allListsSelected() ? 'Unselect All' : 'Select All'}
      </button>
      {lists.map((list) => (
        <div key={list.name}>
          <button onClick={() => handleListCheckboxChange(list.name, list.items)}>
            {allItemsSelected(list.name) ? `Unselect ${list.name}` : `Select ${list.name}`}
          </button>
          {list.items.map((item) => (
            <div key={item}>
              <input
                type="checkbox"
                checked={selectedLists[list.name].includes(item)}
                onChange={() => handleListItemCheckboxChange(list.name, item)}
              />
              {item}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
};

export default App;

代码:https://codesandbox.io/p/sandbox/romantic-borg-qhngwq
如果您有任何建议或最佳实践来提高复选框功能的性能和效率,我将不胜感激,类似于它在 Shopee 购物车页面中的实现方式

我想减少循环开销,并且我正在寻找最佳方法来做到这一点,但我不确定如何做。

javascript reactjs loops object cart
1个回答
0
投票

您可以像这样更改代码:

import React, { useState } from 'react';

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

  const initialSelectedLists = lists.reduce((acc, list) => {
    acc[list.name] = list.items.reduce((itemAcc, item) => {
      itemAcc[item] = false;
      return itemAcc;
    }, {});
    return acc;
  }, {});

  const [selectedLists, setSelectedLists] = useState(initialSelectedLists);

  const toggleListSelection = (listName) => {
    setSelectedLists(prevState => {
      const newListState = { ...prevState };
      const allSelected = Object.values(newListState[listName]).every(value => value);
      newListState[listName] = Object.fromEntries(lists.find(list => list.name === listName).items.map(item => [item, !allSelected]));
      return newListState;
    });
  };

  const toggleAllListsSelection = () => {
    setSelectedLists(prevState => {
      const newListState = {};
      const anyListUnselected = lists.some(list => {
        const { name, items } = list;
        return Object.values(prevState[name]).some(value => !value);
      });
      lists.forEach(list => {
        const { name, items } = list;
        newListState[name] = anyListUnselected ? Object.fromEntries(items.map(item => [item, true])) : {};
      });
      return newListState;
    });
  };

  const toggleItemSelection = (listName, item) => {
    setSelectedLists(prevState => {
      const newListState = { ...prevState };
      newListState[listName][item] = !newListState[listName][item];
      return newListState;
    });
  };

  const allItemsSelected = (listName) => {
    return Object.values(selectedLists[listName]).every(value => value);
  };

  const allListsSelected = () => {
    return lists.every(list => allItemsSelected(list.name));
  };

  return (
    <div>
      <button onClick={toggleAllListsSelection}>
        {allListsSelected() ? 'Unselect All' : 'Select All'}
      </button>
      {lists.map(list => (
        <div key={list.name}>
          <button onClick={() => toggleListSelection(list.name)}>
            {allItemsSelected(list.name) ? `Unselect ${list.name}` : `Select ${list.name}`}
          </button>
          {list.items.map(item => (
            <div key={item}>
              <input
                type="checkbox"
                checked={selectedLists[list.name][item]}
                onChange={() => toggleItemSelection(list.name, item)}
              />
              {item}
            </div>
          ))}
        </div>
      ))}
    </div>
  );
};

export default App;

这避免了不必要的状态更新,目前,每当选择发生变化时,整个状态对象 selectedLists 都会更新。 此外,您可以使用对象,其中键代表项目名称,值代表项目是否被选择,而不是使用数组来跟踪每个列表中的选定项目。一些事件处理程序也被重构。

© www.soinside.com 2019 - 2024. All rights reserved.