繁体   English   中英

处理带有嵌套对象数组的复选框

[英]Handling checkboxes with nested array of objects

我有一个呈现多个复选框的组件。 每个复选框都是动态处理的,它们的checked属性在渲染时被分配。 我需要打印/渲染所选复选框的值。 这是示例 state 的样子:

{
        Filters: [
          {
            name: "Vegetables",
            options: [
              {
                value: "tmto",
                name: "Tomato"
              },
              {
                value: "ptato",
                name: "Potato"
              }
            ]
          },
          {
            name: "Fruits",
            options: [
              {
                value: "ornge",
                name: "Orange"
              },
              {
                value: "grps",
                name: "Grapes"
              }
            ]
          }
        ],
      selected: []
    }

我首先映射一个类别名称,然后再次使用相应的值和名称映射checkboxes ,例如:

Vegetables
checkbox 1
checkbox 2

Fruits
checkbox 3
checkbox 4

我有一个相同的https://codesandbox.io/s/react-functional-component-forked-wb1ew的工作片段,但不确定为什么它无法设置与所选复选框匹配的 state。 我对如何处理这个嵌套的复选框 state 有点困惑。

非常感谢任何解决此问题的帮助。

我分叉了您的 CodeSandbox 并应用了修复程序。 您可以在下面找到一个可行的解决方案。

https://codesandbox.io/s/react-functional-component-forked-gmwv0


有相当多的地方需要改变,但我会尽力覆盖它。

  1. 您在this.setState中引用了 this.setState,这在功能组件中不起作用。 在功能组件中,您使用 useState 钩子的第二个参数,在这种情况下等于setState 功能组件不将this用于任何内部方法。
  2. 您的渲染 function 内部存在无效语法。 您需要确保始终返回带有单个顶级包装组件的 JSX object。
  3. 问题的 rest 在您的 handleCheckboxChange 内。 由于 setState 的异步特性,最好使用 setState 内部的回调,即setState((prevState) => {}) ,这将确保您没有过时的 state。 您还需要从中返回 object,这将是您的新 state。
  4. 我更新了复选框的值(选中)以使用您在此 function 中计算的选定值。
  5. 我做的最后一件事是更新映射以正确返回格式正确的 state。

最终解决方案

const App = (props) => {
  const [state, setState] = useState({
    Filters: [
      {
        name: "Vegetables",
        options: [
          {
            value: "tmto",
            name: "Tomato"
          },
          {
            value: "ptato",
            name: "Potato"
          }
        ]
      },
      {
        name: "Fruits",
        options: [
          {
            value: "ornge",
            name: "Orange"
          },
          {
            value: "grps",
            name: "Grapes"
          }
        ]
      }
    ],
    selected: []
  });

  const handleCheckboxChange = (value) => {
    setState((state) => {
      const updatedEtables = state.selected.find((obj) => obj === value);
      const selected = updatedEtables
        ? state.selected.filter((obj) => obj !== value)
        : [...state.selected, value];

      return {
        selected,
        Filters: [
          ...state.Filters.map((filter) => {
            return {
              ...filter,
              options: filter.options.map((ele) => {
                return {
                  ...ele,
                  checked: selected.includes(ele.value)
                };
              })
            };
          })
        ]
      };
    });
  };

  return (
    <div>
      {state.Filters.map((ele) => {
        return (
          <React.Fragment>
            <h6>{ele.name}</h6>
            {ele.options.map((item) => {
              return (
                <div>
                  <input
                    checked={item.checked || false}
                    onChange={() => handleCheckboxChange(item.value)}
                    type="checkbox"
                  />
                </div>
              );
            })}
          </React.Fragment>
        );
      })}

      <strong>Selected: </strong>
      <br />
      <span>{state.selected.join(",")}</span>
    </div>
  );
};

链接代码会引发错误,因为{...}符号必须始终夹在标签之间。

以下是无效的 JSX:

return (
  <h1>Hello World!</h1>
  {data}
);

JSX 必须始终只有一个根组件。 如果要返回多个根级组件,请将它们包装在React.Fragment中。

上面无效的例子应该写成:

return (
  <React.Fragment>
    <h1>Hello World!</h1>
    {data}
  </React.Fragment>
);

这确保只有一个根组件可以解决您的错误。


将此应用于您的代码会改变:

 return ( <div> {state.Filters.map(ele => { return ( <h6>{ele.name}</h6> {ele.options.map(item => { return ( <div> <input checked={item.checked} onChange={() => handleCheckboxChange(item.value)} type="checkbox" /> </div> ) })} ) })} <strong>Selected: </strong> <br /> <span>{state.selected.join(",")}</span> </div> );

进入:

return (
  <div>
    {state.Filters.map(ele => {
      return (
        <React.Fragment>
          <h6>{ele.name}</h6>
          {ele.options.map(item => {
            return (
              <div>
                <input 
                  checked={item.checked}
                  onChange={() => handleCheckboxChange(item.value)}
                  type="checkbox"
                />
              </div>
            )
          })}
        </React.Fragment>
      )
    })}
    <strong>Selected: </strong>
    <br />
    <span>{state.selected.join(",")}</span>
  </div>
);

注意React.Fragment的使用。 您还可以使用更新的短语法( <>...</> ),它看起来更简洁( 但缺少一些工具支持)。 您还可以使用箭头函数的隐式返回值进一步清理代码。

return (
  <div>
    {state.Filters.map(ele => (
      <>
        <h6>{ele.name}</h6>
        {ele.options.map(item => (
          <div>
            <input 
              checked={item.checked}
              onChange={() => handleCheckboxChange(item.value)}
              type="checkbox"
            />
          </div>
        ))}
      </>
    ))}
    <strong>Selected: </strong>
    <br />
    <span>{state.selected.join(",")}</span>
  </div>
);

在@Chris 的帮助和@3limin4t0r 的宝贵投入的帮助下,我正在这里编译最终的工作代码,正如@ggorlen 所建议的那样,以供将来可能遇到相同问题或问题的人使用:

import React, { useState } from "react";
import { render } from "react-dom";

const App = (props) => {
  const [state, setState] = useState({
    Filters: [
      {
        name: "Vegetables",
        options: [
          {
            value: "tmto",
            name: "Tomato"
          },
          {
            value: "ptato",
            name: "Potato"
          }
        ]
      },
      {
        name: "Fruits",
        options: [
          {
            value: "ornge",
            name: "Orange"
          },
          {
            value: "grps",
            name: "Grapes"
          }
        ]
      }
    ],
    selected: []
  });

  const handleCheckboxChange = (value) => {
    setState((state) => {
      const updatedEtables = state.selected.find(
        (obj) => obj === value
      );
      const selected = updatedEtables
        ? state.selected.filter(
            (obj) => obj !== value
          )
        : [...state.selected, value];

      return {
        selected,
        Filters: [
          ...state.Filters.map((filter) => {
            return {
              ...filter,
              options: filter.options.map((ele) => {
                return {
                  ...ele,
                  checked: selected.includes(ele.value)
                };
              })
            };
          })
        ]
      };
    });
  };

  return (
    <div>
      {state.Filters.map((ele) => {
        return (
          <React.Fragment>
            <h6>{ele.name}</h6>
            {ele.options.map((item) => {
              return (
                <div>
                  <input
                    checked={item.checked || false}
                    onChange={() => handleCheckboxChange(item.value)}
                    type="checkbox"
                  />
                </div>
              );
            })}
          </React.Fragment>
        );
      })}

      <strong>Selected: </strong>
      <br />
      <span>{state.selected.join(",")}</span>
    </div>
  );
};

render(<App />, document.getElementById("root"));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM