如何基于props数组创建多个React useState

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

如何基于数组创建多个useState并跟踪变化?或者只是将单个状态对象传递给多个组件?

在组件的底部,我尝试基于

customFilter
数组在循环中创建
options

import * as React from 'react';

import TransferList from './TransferList';
import Accordion from '@mui/material/Accordion';
import AccordionSummary from '@mui/material/AccordionSummary';
import AccordionDetails from '@mui/material/AccordionDetails';
import Typography from '@mui/material/Typography';
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';

export default function CustomFormatBox() {
  const options = [
    {
      name: 'sample_type_key',
      label: 'Sample Type',
      defaultOperator: 'in',
      valueEditorType: 'multiselect',
      values: [
        { name: '0', label: 'OPTICAL_BLANK_0' },
        { name: '1', label: 'OPTICAL_BLANK_1' },
      ],
    },
    {
      name: 'cuvette_number',
      label: 'Cuvette Number',
      defaultOperator: 'in',
      valueEditorType: 'multiselect',
      values: [
        { name: '0', label: '0' },
        { name: '1', label: '1' },
        { name: '2', label: '2' },
      ],
    },
    {
      name: 'wavelength_key',
      label: 'Wavelength',
      values: [
        { name: '0', label: '340nm' },
        { name: '8', label: '850nm' },
      ],
    },
  ];

  const [filters, setFilters] = React.useState([]);
  const [filters2, setFilters2] = React.useState([]);

  // How to merge multiple state into single object?
  const [allFilters, setAllFilters] = React.useState({
    sample_type_key: [],
    cuvette_number: [],
  });

  const customFilter = (option, right, setRight) => (
    <Accordion>
      <AccordionSummary
        expandIcon={<ArrowDownwardIcon />}
        aria-controls={`panel-${option.label}-content`}
        id={`panel-${option.label}-header`}
      >
        <Typography>{option.label}</Typography>
      </AccordionSummary>
      <AccordionDetails>
        <TransferList option={option} name right={right} setRight={setRight} />
        <table>
          <tbody>
            {right.map((item) => (
              <tr key={item.name}>
                <td>{item.label}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </AccordionDetails>
    </Accordion>
  );

  return (
<>
      {/* Eventually would like to create these filters in a loop based on options array. */}
      {customFilter(options[0], filters, setFilters)}
      {customFilter(options[1], filters2, setFilters2)}

      {/* How to tell setAllFilters to set only in cuvette_number?  */}
      {customFilter(options[1], allFilters['cuvette_number'], () => {
        setAllFilters((state) => ({ ...state, cuvette_number: state }));
      })}
      {/* Do not know how to do the update state part */}
    </>
  );
}

工作 Stackblitz:https://stackblitz.com/edit/vite-react-state?file=src%2Fcomponents%2FCustomFormatBox.jsx

javascript reactjs react-hooks
2个回答
0
投票

根据 @evolutionxbox 评论,带有

useReducer

的版本
import * as React from 'react';

import TransferList from "./TransferList"
import Accordion from '@mui/material/Accordion';
import AccordionSummary from '@mui/material/AccordionSummary';
import AccordionDetails from '@mui/material/AccordionDetails';
import Typography from '@mui/material/Typography';
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';

export function createInitialState(options) {
    const emptyListsFromOptionsName = options.map((o) => [o.name, []])

    const objWithLists = Object.fromEntries(emptyListsFromOptionsName);

    return objWithLists;
}

function reducer(state, action) {
    const result = {
        ...state
    };
    result[action.type] = action.right;
    return result;
}

export default function CustomFormatBox() {

    const options = [{
        name: "sample_type_key",
        label: "Sample Type",
        defaultOperator: "in",
        valueEditorType: "multiselect",
        values: [
            { name: "0", label: "OPTICAL_BLANK_0" },
            { name: "1", label: "OPTICAL_BLANK_1" },
            { name: "2", label: "OPTICAL_BLANK_2" },
            { name: "8", label: "OPTICAL_BLANK_8" },
            { name: "10", label: "SAMPLE_BLANK_0" },
            { name: "11", label: "SAMPLE_BLANK_1" },
            { name: "20", label: "SYS_CUV_6" },
            { name: "21", label: "SYS_CUV_11" },
            { name: "22", label: "SYS_CUV_28" },
            { name: "253", label: "OPTICAL_DACS" }
        ]
    },
    {
        name: "cuvette_number",
        label: "Cuvette Number",
        defaultOperator: "in",
        valueEditorType: "multiselect",
        values: [
            { name: "0", label: "0" },
            { name: "1", label: "1" },
            { name: "2", label: "2" }
        ]
    },
    {
        name: "wavelength_key",
        label: "Wavelength",
        values: [
            { name: "0", label: "340nm" },
            { name: "8", label: "850nm" }
        ]
    }
    ];

    const [filtersAll, dispatch] = React.useReducer(reducer, createInitialState(options));

    const customFilter = (option, right, setRight) => (
        <Accordion key={option.name}>
            <AccordionSummary
                expandIcon={<ArrowDownwardIcon />}
                aria-controls={`panel-${option.label}-content`}
                id={`panel-${option.label}-header`}
            >
                <Typography>{option.label}</Typography>
            </AccordionSummary>
            <AccordionDetails>
                <TransferList option={option} name right={right} setRight={setRight} />
                <table>
                    <tbody>
                        {right.map(item => (
                            <tr key={item.name}>
                                <td>{item.label}</td>
                            </tr>
                        ))}
                    </tbody>
                </table>
            </AccordionDetails>
        </Accordion>
    );

    return (
        <div>
            {options.map((option) => {
                return customFilter(option, filtersAll[option.name], (right) => dispatch({ type: option.name, right: right }))
            })}
        </div>
    )
}

0
投票

一般来说不建议基于数组生成状态,这样最终会导致状态难以管理。在这种情况下,也许可以考虑使用单个状态对象。我根据您现有的代码做了一些更改,希望对您有所帮助!

https://stackblitz.com/edit/vite-react-state-vwd49u?file=src%2Fcomponents%2FCustomFormatBox.jsx

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