【问题标题】:How to toggle between values in a nested object如何在嵌套对象中的值之间切换
【发布时间】:2020-02-18 19:09:46
【问题描述】:

我有一个名为 useToggles 的 React 钩子,用于我的应用程序中的各种复选框和单选按钮。到目前为止,我已经能够摆脱类似以下的事情:

const useToggles = (initialValues = {}) => {
  const [toggleValues, setToggleValues] = useState(initialValues);

  const handleToggle = e => {
    const name = e.currentTarget.attributes.name.value;
    const value = toggleValues[e.currentTarget.attributes.name.value];

    setToggleValues(values => ({ ...values, [name]: !value }));
  };

  return {
    toggleValues,
    setToggleValues,
    handleToggle,
  };
};

export default useToggles;

一个示例复选框组件:

<CheckBox
   checked={toggleValues.gluten || false}
   label="Gluten"
   onChange={handleToggle}
   name="gluten"
 />

因此,尽管我的“toggleValues”对象以 {} 开头,但只要选中复选框,它就会填充该对象。所以我们可能有:

{
  gluten: true,
  soy: false
}

因为这个对象只有一层,所以展开值并使用[name]: !value 翻转布尔值将起作用。

但是,当需要更多的组织时,这就会分崩离析。在另一页上,我有几组复选框,我需要将它们的值组合在一起以填充各个数据库字段。为了处理这个问题,我在复选框中添加了一层组织:

 <CheckBox
      checked={toggleValues.dietType.paleo || ''}
      label="Paleo"
      onChange={handleToggle}
      name="dietType.paleo"
    />

我们在应用程序的其他地方使用了这种组织方法来对数据进行分组,并使用点对象解析字符串。示例来自 useFormValues():dot.str(e.target.name, value, tmp);

此方法不适用于 useToggles,因为我们依赖于 toggleValues 对象中先前存在的数据。每次单击复选框时,使用 dot-object 始终会创建对象的新层。但是我还没有找到一种使用 [name] 来选择对象的第二级或第三级的方法。

为了可视化这一点,我需要做的是获取这个对象并根据接收名称“dietType.paleo”的函数将paleo的值翻转为true:

{
    dietType: {
      paleo: true;
    },
    intolerances: {}
  }

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    您可以使用柯里化并将复选框组名称作为参数传递给handleToggle

    const handleToggle = sub => e => {
      const name = e.currentTarget.attributes.name.value;
      if (!sub) setToggleValues({ ...toggleValues, [name]: !toggleValues[name] });
      else {
        const newSub = { ...toggleValues[sub], [name]: !toggleValues[sub][name] };
        setToggleValues({ ...toggleValues, [sub]: newSub });
      }
    };
    

    现在将onChange={handleToggle()} 用于顶层,onChange={handleToggle("dietType")} 用于古复选框。

    编辑:
    另一种方法是检查name 中是否有句点并相应地分支:

    const handleToggle = e => {
      const name = e.currentTarget.attributes.name.value;
      if (!~name.indexOf("."))
        setToggleValues({ ...toggleValues, [name]: !toggleValues[name] });
      else {
        const [sub, prop] = name.split(".");
        const newSub = { ...toggleValues[sub], [prop]: !toggleValues[sub][prop] };
        setToggleValues({ ...toggleValues, [sub]: newSub });
      }
    };
    

    这样你可以保持现有的 JSX 1:1。

    【讨论】:

    • 谢谢,这成功了!另一个注意事项是需要将“名称”属性从 name: "dietType.paleo" 更改为简单的 name: "paleo"
    • @ipenguin67 是的,这让我重新思考了我的方法;我在我的答案中添加了一个替代版本,让你保留你的 JSX。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-21
    • 2022-11-01
    • 2016-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    相关资源
    最近更新 更多