首页 > 解决方案 > 如何在嵌套对象中的值之间切换

问题描述

我有一个名为 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"
    />

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

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

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

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

标签: javascriptreactjs

解决方案


您可以使用 currying 并将复选框组名称作为参数传递给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。


推荐阅读