使用嵌套对象数组处理复选框
我有一个可渲染多个复选框的组件。每个复选框都通过其
checked
属性进行动态处理,并在渲染时进行分配。我需要打印/渲染选中复选框的值。
示例状态如下所示:
{
Filters: [
{
name: "Vegetables",
options: [
{
value: "tmto",
name: "Tomato"
},
{
value: "ptato",
name: "Potato"
}
]
},
{
name: "Fruits",
options: [
{
value: "ornge",
name: "Orange"
},
{
value: "grps",
name: "Grapes"
}
]
}
],
selected: []
}
我首先映射类别名称,然后再次使用相应的值和名称映射
checkbox
,例如:
Vegetables
checkbox 1
checkbox 2
Fruits
checkbox 3
checkbox 4
我有一个适用于相同 https://codesandbox.io/s/react- functional-component-forked-wb1ew 的工作代码片段,但不确定为什么它无法设置与选中复选框匹配的状态。 我对如何处理这种嵌套复选框状态有点困惑。
任何有助于解决此问题的帮助都将不胜感激。
我分叉了您的 CodeSandbox 并应用了修复。您可以在下面找到可行的解决方案。
https://codesandbox.io/s/react- functional-component-forked-gmwv0
有很多需要更改的地方,但我会尽力介绍。
-
您在 handleCheckboxChange 中引用了
this.setState
,这在功能组件中不起作用。在功能组件中,您使用 useState 钩子的第二个参数,在本例中等于setState
。功能组件不会将this
用于任何内部方法。 - 您的渲染函数内部存在无效语法。您需要确保始终返回带有单个顶级包装组件的 JSX 对象。
-
其余问题都出现在您的 handleCheckboxChange 中。由于 setState 的异步特性,最好在 setState 内部使用回调,即
setState((prevState) => {})
,这将确保您没有陈旧状态。您还需要从中返回一个对象,这将是您的新状态。 - 我更新了复选框的值(已选中),以使用您在此函数中计算的选定值。
- 我做的最后一件事是更新映射以正确返回正确格式的状态。
最终解决方案
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"));