我如何在 React 中控制多个复选框?
How do I control multiple checkboxes in React?
我在组件中有一个主复选框和其他多个复选框
代码:
const Filter = () => {
const [checkBoxes, setCheckBoxes] = useState([
{id: 'without', label: "Без пересадок", isChecked: true},
{id: 'one', label: "1 пересадка", isChecked: true},
{id: 'two', label: "2 пересадки", isChecked: true},
{id: 'three', label: "3 пересадки", isChecked: true}
])
const [mainCheckbox, setMainCheckbox] = useState({
id: 'all', label: "Все", isChecked: true
})
const allCheckBoxesChange = ({ target : { checked } }) => {
setMainCheckbox({
...mainCheckbox,
isChecked: checked
})
let allCheckBoxes = [...checkBoxes]
allCheckBoxes.forEach(item => {
item.isChecked = checked
})
setCheckBoxes(allCheckBoxes)
}
const checkBoxChange = ({ target : { name, checked } }) => {
let newCheckBoxes = [...checkBoxes]
newCheckBoxes.forEach(item => {
if (item.id === name) {
item.isChecked = checked
}
})
setCheckBoxes(newCheckBoxes)
}
return (
<div className="content__filter">
<div className="content__filter__name">
Количество пересадок
</div>
<div className="content__filter__list">
<div className="content__filter__item">
<input
type="checkbox"
id={mainCheckbox.id}
name={mainCheckbox.id}
checked={mainCheckbox.isChecked}
onChange={allCheckBoxesChange}
/>
<label htmlFor={mainCheckbox.id}>{mainCheckbox.label}</label>
</div>
<ul>
{checkBoxes.map(item => (
<CheckBox
key={item.id}
id={item.id}
name={item.id}
htmlFor={item.id}
label={item.label}
checked={item.isChecked}
onChange={checkBoxChange}
/>
))}
</ul>
</div>
</div>
);
};
const CheckBox = ({
type = "checkbox",
name,
htmlFor,
label,
onChange,
checked,
id,
}) => {
return (
<div className="content__filter__item">
<input
type={type}
id={id}
name={name}
checked={checked}
onChange={onChange}
/>
<label htmlFor={htmlFor}>{label}</label>
</div>
)
};
如您所见,主复选框和其他复选框由单独的状态和单独的 onChange
函数控制。一切正常,但有一个误解的时刻。如果我选中主复选框,则所有其他复选框都会被选中。如果我取消选中任何其他复选框,我需要取消选中我的主复选框。相反,如果我的所有其他复选框都被选中,我还需要选中我的主复选框。
在我的情况下我该怎么做?
当您更改复选框时,如果有任何未选中或现在全部选中,则不会更新主复选框。
在您的方法 checkBoxChange 中,您必须验证两种状态:
如果 4 个复选框中的任何内容未选中 - 也取消选中主复选框。
如果 3 个复选框是 checkend,而您碰巧将第四个复选框选中为完整检查 - 更新主复选框并选中。
基本上您需要做的是在检查复选框时添加一个简单的检查并询问主要状态和所有其他状态是什么。
这是带示例的codesandbox:https://codesandbox.io/s/trusting-mendel-0hvrl?file=/src/App.js
这是为支持这种情况而修改的代码:
const Filter = () => {
const [checkBoxes, setCheckBoxes] = useState([
{id: 'without', label: "Без пересадок", isChecked: true},
{id: 'one', label: "1 пересадка", isChecked: true},
{id: 'two', label: "2 пересадки", isChecked: true},
{id: 'three', label: "3 пересадки", isChecked: true}
])
const [mainCheckbox, setMainCheckbox] = useState({
id: 'all', label: "Все", isChecked: true
})
const allCheckBoxesChange = ({ target : { checked } }) => {
const newMainCheckbox = {
...mainCheckbox,
isChecked: checked
}
setMainCheckbox(newMainCheckbox)
// Check what other checkboxes state need to be
let allCheckBoxes = [...checkBoxes]
allCheckBoxes.forEach(item => {
item.isChecked = newMainCheckbox.isChecked;
})
setCheckBoxes(allCheckBoxes)
}
const checkBoxChange = ({ target : { name, checked } }) => {
let newCheckBoxes = [...checkBoxes]
newCheckBoxes.forEach(item => {
if (item.id === name) {
item.isChecked = checked
}
})
setCheckBoxes(newCheckBoxes)
// Check what state should main be
const isEveryBoxChecked = newCheckBoxes.every((value) => value.isChecked)
setMainCheckbox({...mainCheckbox, isChecked: isEveryBoxChecked})
}
return (
<div className="content__filter">
<div className="content__filter__name">
Количество пересадок
</div>
<div className="content__filter__list">
<div className="content__filter__item">
<input
type="checkbox"
id={mainCheckbox.id}
name={mainCheckbox.id}
checked={mainCheckbox.isChecked}
onChange={allCheckBoxesChange}
/>
<label htmlFor={mainCheckbox.id}>{mainCheckbox.label}</label>
</div>
<ul>
{checkBoxes.map(item => (
<CheckBox
key={item.id}
id={item.id}
name={item.id}
htmlFor={item.id}
label={item.label}
checked={item.isChecked}
onChange={checkBoxChange}
/>
))}
</ul>
</div>
</div>
);
};
const CheckBox = ({
type = "checkbox",
name,
htmlFor,
label,
onChange,
checked,
id,
}) => {
return (
<div className="content__filter__item">
<input
type={type}
id={id}
name={name}
checked={checked}
onChange={onChange}
/>
<label htmlFor={htmlFor}>{label}</label>
</div>
)
};
我在组件中有一个主复选框和其他多个复选框
代码:
const Filter = () => {
const [checkBoxes, setCheckBoxes] = useState([
{id: 'without', label: "Без пересадок", isChecked: true},
{id: 'one', label: "1 пересадка", isChecked: true},
{id: 'two', label: "2 пересадки", isChecked: true},
{id: 'three', label: "3 пересадки", isChecked: true}
])
const [mainCheckbox, setMainCheckbox] = useState({
id: 'all', label: "Все", isChecked: true
})
const allCheckBoxesChange = ({ target : { checked } }) => {
setMainCheckbox({
...mainCheckbox,
isChecked: checked
})
let allCheckBoxes = [...checkBoxes]
allCheckBoxes.forEach(item => {
item.isChecked = checked
})
setCheckBoxes(allCheckBoxes)
}
const checkBoxChange = ({ target : { name, checked } }) => {
let newCheckBoxes = [...checkBoxes]
newCheckBoxes.forEach(item => {
if (item.id === name) {
item.isChecked = checked
}
})
setCheckBoxes(newCheckBoxes)
}
return (
<div className="content__filter">
<div className="content__filter__name">
Количество пересадок
</div>
<div className="content__filter__list">
<div className="content__filter__item">
<input
type="checkbox"
id={mainCheckbox.id}
name={mainCheckbox.id}
checked={mainCheckbox.isChecked}
onChange={allCheckBoxesChange}
/>
<label htmlFor={mainCheckbox.id}>{mainCheckbox.label}</label>
</div>
<ul>
{checkBoxes.map(item => (
<CheckBox
key={item.id}
id={item.id}
name={item.id}
htmlFor={item.id}
label={item.label}
checked={item.isChecked}
onChange={checkBoxChange}
/>
))}
</ul>
</div>
</div>
);
};
const CheckBox = ({
type = "checkbox",
name,
htmlFor,
label,
onChange,
checked,
id,
}) => {
return (
<div className="content__filter__item">
<input
type={type}
id={id}
name={name}
checked={checked}
onChange={onChange}
/>
<label htmlFor={htmlFor}>{label}</label>
</div>
)
};
如您所见,主复选框和其他复选框由单独的状态和单独的 onChange
函数控制。一切正常,但有一个误解的时刻。如果我选中主复选框,则所有其他复选框都会被选中。如果我取消选中任何其他复选框,我需要取消选中我的主复选框。相反,如果我的所有其他复选框都被选中,我还需要选中我的主复选框。
在我的情况下我该怎么做?
当您更改复选框时,如果有任何未选中或现在全部选中,则不会更新主复选框。
在您的方法 checkBoxChange 中,您必须验证两种状态:
如果 4 个复选框中的任何内容未选中 - 也取消选中主复选框。
如果 3 个复选框是 checkend,而您碰巧将第四个复选框选中为完整检查 - 更新主复选框并选中。
基本上您需要做的是在检查复选框时添加一个简单的检查并询问主要状态和所有其他状态是什么。
这是带示例的codesandbox:https://codesandbox.io/s/trusting-mendel-0hvrl?file=/src/App.js
这是为支持这种情况而修改的代码:
const Filter = () => {
const [checkBoxes, setCheckBoxes] = useState([
{id: 'without', label: "Без пересадок", isChecked: true},
{id: 'one', label: "1 пересадка", isChecked: true},
{id: 'two', label: "2 пересадки", isChecked: true},
{id: 'three', label: "3 пересадки", isChecked: true}
])
const [mainCheckbox, setMainCheckbox] = useState({
id: 'all', label: "Все", isChecked: true
})
const allCheckBoxesChange = ({ target : { checked } }) => {
const newMainCheckbox = {
...mainCheckbox,
isChecked: checked
}
setMainCheckbox(newMainCheckbox)
// Check what other checkboxes state need to be
let allCheckBoxes = [...checkBoxes]
allCheckBoxes.forEach(item => {
item.isChecked = newMainCheckbox.isChecked;
})
setCheckBoxes(allCheckBoxes)
}
const checkBoxChange = ({ target : { name, checked } }) => {
let newCheckBoxes = [...checkBoxes]
newCheckBoxes.forEach(item => {
if (item.id === name) {
item.isChecked = checked
}
})
setCheckBoxes(newCheckBoxes)
// Check what state should main be
const isEveryBoxChecked = newCheckBoxes.every((value) => value.isChecked)
setMainCheckbox({...mainCheckbox, isChecked: isEveryBoxChecked})
}
return (
<div className="content__filter">
<div className="content__filter__name">
Количество пересадок
</div>
<div className="content__filter__list">
<div className="content__filter__item">
<input
type="checkbox"
id={mainCheckbox.id}
name={mainCheckbox.id}
checked={mainCheckbox.isChecked}
onChange={allCheckBoxesChange}
/>
<label htmlFor={mainCheckbox.id}>{mainCheckbox.label}</label>
</div>
<ul>
{checkBoxes.map(item => (
<CheckBox
key={item.id}
id={item.id}
name={item.id}
htmlFor={item.id}
label={item.label}
checked={item.isChecked}
onChange={checkBoxChange}
/>
))}
</ul>
</div>
</div>
);
};
const CheckBox = ({
type = "checkbox",
name,
htmlFor,
label,
onChange,
checked,
id,
}) => {
return (
<div className="content__filter__item">
<input
type={type}
id={id}
name={name}
checked={checked}
onChange={onChange}
/>
<label htmlFor={htmlFor}>{label}</label>
</div>
)
};