如何让每个组件共享状态多个受控复选框选择在React中唯一?

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

我的左侧有几个组件。我正在对他们运行地图。每个组件都有一个基于组件 id 的 switch.so,单击 switch 后,右侧将打开一个复选框列表。 然后我还在复选框上运行地图,因为这些数据来自后端。 例如,组件 1 具有具有以下名称的复选框列表。 复选框-1 复选框-2 如果我选择复选框 1,然后单击组件 2 开关,那么将显示此组件 2 的复选框列表。 问题是,如果组件 2 的复选框名称与组件 1 相同,组件 2 的复选框名称也会被检查。 如何保持它们的独特性? 我希望每个组件复选框选择都是唯一的。 这是我到目前为止所做的。 (1) 我将密钥传递给组件。因此,每当 id 更改时,都会重新渲染 ui。但它不起作用。 (2)目前我的复选框状态位于父组件中,我查看了反应文档,根据它,状态应该是组件本地的。我将复选框状态移动到复选框组件中,然后我的问题得到解决。但我需要在父级中选择复选框,因为我正在与其他组件共享它。 (3) 然后我实现 redux-saga。但仍然是同样的问题,然后我实现了 context api,这也没有解决我的问题。

我正在分享我的handlechange代码。这就是管理它们的方式。

  const handleChange = event => {
    const { name, checked } = event.target;
    if (checked) {
      setCheckedItems({ ...checkedItems, [name]: true });
    } else {
      const { [name]: deletedItem, ...updatedCheckedItems } = checkedItems;
      setCheckedItems(updatedCheckedItems);
    }
  };

(4) 然后我想也许我应该制作一个像这样的数据结构,当用户选中任何复选框时,每个组件唯一的 id 应该有自己的复选框选择。 这就是那个代码。

  const handleChange = (event, componentId, index) => {
    const { name, checked } = event.target;

    setCheckboxIndex(index);

    // Update the state using the componentId to ensure uniqueness
    setCheckedItems(prevItems => {
      // Get the previous state for the component or initialize it
      const componentState = prevItems[componentId] || { checkboxes: {} };
      // Clone the previous component state
      const updatedComponentState = { ...componentState };

      if (checked) {
        updatedComponentState.checkboxes = {
          ...updatedComponentState.checkboxes,
          [name]: true,
        };
      } else {
        // Remove the checkbox from the component's state
        const {
          [name]: deletedItem,
          ...updatedCheckboxes
        } = updatedComponentState.checkboxes;
        updatedComponentState.checkboxes = updatedCheckboxes;
      }

      // Update the overall state with the new component state
      return {
        ...prevItems,
        [componentId]: updatedComponentState,
      };
    });
  };

但这也没有解决我的问题。 这也是当前在 context.js 中的代码 现在我正在分享我的组件看起来如何相似。

 (toggleMenu === 'feedback' &&
              Object.keys(feedback).includes(String(q.id))) ||
            (q.question.question_type === 'assignment' &&
              toggleAll === 'auto') ? (
              <Grid item xs={5} className={classes.questionWrapper} key={q.id}>
                <NewFeedback
                  key={q.id}
                  assignmentIndex={qidx}
                  markingData={automatedMarkingData}
                  questionId={q.question.id}
                  qId={qId}
                  fetchMarkingData={fetchMarkingData}
                  status={assignmentStatus}
                />
              </Grid>

每当用户单击组件开关时,我都会更新此状态。 反馈 然后根据内部反馈的 id,我打开复选框组件。

组件NewFeedback是checkbox组件所在的组件,名称为sidebar.js

<SideBar
        bow={bow}
        checkedItems={checkedItems}
        handleSelectAll={handleSelectAll}
        handleChange={handleChange}
        allSelected={allSelected}
        assignmentId={markingData.question_submission}
        assignmentIndex={assignmentIndex}
        checkboxIndex={checkboxIndex}
      />

这是我的 sidebar.js 代码

import React, { useContext } from 'react';
import {
  Box,
  Checkbox,
  Divider,
  FormControlLabel,
  FormGroup,
  LinearProgress,
  Paper,
  Typography,
} from '@material-ui/core';
import styles from './styles.css';
import { LessonContext } from '../../LessonViewer/GoProgressQuizResult/Context';

export const SideBar = ({
  bow,
  checkedItems,
  handleSelectAll,
  handleChange,
  allSelected,
  assignmentId,
  assignmentIndex,
  checkboxIndex,
}) => {
  return (
    <Paper elevation={0} className={`${styles.FeedbackSideMenu}`}>
      <Box p={1}>
        <Typography align="center">
          <b>All BOW</b>
        </Typography>
      </Box>
      <Divider style={{ margin: '5px 0' }} />
      <Box style={{ overflowY: 'scroll' }}>
        <FormGroup>
          <FormControlLabel
            style={{ display: 'flex', justifyContent: 'space-evenly' }}
            control={
              <Checkbox
                checked={allSelected}
                onChange={handleSelectAll}
                name="selectAll"
                color="primary"
              />
            }
            label="Select All"
          />
        </FormGroup>
        {bow.map((v, index) => {
          // const isChecked =
          //   (checkedItems[assignmentId] &&
          //     checkedItems[assignmentId].checkboxes[v.bow_name]) ||
          //   false;

          // console.log('isChecked', isChecked);
          return (
            <div key={v.id}>
              <Box className={`${styles.FeedbackOption}`}>
                <Box
                  display={'flex'}
                  justifyContent="space-between"
                  alignItems="center"
                >
                  <Checkbox
                    id={v.id}
                    // checked={checkedItems[`${v.bow_name}_${v.id}`] || false}
                    checked={checkedItems[v.bow_name] || false}
                    // checked={label === v.bow_name ? true : false}
                    // checked={isChecked}
                    onChange={e => handleChange(e, assignmentId, index)}
                    name={v.bow_name}
                    color="primary"
                  />
                  <Typography>
                    <b>{v.bow_name}</b>
                  </Typography>
                  <Box bgcolor={`${v.color}`} width={20} height={20} />
                </Box>

                <Typography>
                  <small>{v.sum_count} count</small>
                </Typography>
                <LinearProgress
                  variant="determinate"
                  value={v.sum_count ? v.sum_count : 0}
                />
              </Box>
              <Divider style={{ margin: '5px 0' }} />
            </div>
          );
        })}
      </Box>
    </Paper>
  );
};

抱歉,我无法制作沙盒,因为我的实际代码库非常大。 这是我的用户界面图像,以便更好地理解。

javascript reactjs checkbox material-ui
1个回答
0
投票

我解决了这个问题。 NewFeedback 组件位于地图内,因此我只需将我的提供程序包装在 NewFeedback 组件上的地图内。这样每个组件都有自己的状态和复选框选择。

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