- 首页
- 其他开发
- ReactJS:使用 useState 管理多个复选框输入
ReactJS:使用 useState 管理多个复选框输入
[英] ReactJS: Manage multiple checkbox inputs with useState
本文介绍了ReactJS:使用 useState 管理多个复选框输入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有以下示例组件,它使用多个复选框来选择要从对象列表中删除的项目:
import React, { useState } from "react";导入./styles.css";常量数据 = [{名称:测试1",结果:通过"},{名称:测试2",结果:通过"},{名称:test3",结果:通过"},{名称:test4",结果:通过"},{名称:测试5",结果:通过"}];导出默认函数 App() {const [allChecked, setAllChecked] = useState(false);const [isChecked, setIsChecked] = useState({});const [formData, setFormData] = useState(data);const handleAllCheck = e =>{setAllChecked(e.target.checked);};const handleSingleCheck = e =>{setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });};const onDelete = () =>{console.log(isChecked);const newData = data.filter(项目 =>!Object.keys(isChecked).includes(item.name));控制台日志(新数据);setFormData(newData);};返回 (<div className="应用程序"><div><label>All</label><输入名称=checkall"类型=复选框"已检查={allChecked}onChange={handleAllCheck}/><标签/>
{formData.map((test, index) => (<div key={index}><label>{test.name}</label><输入类型=复选框"名称={test.name}已检查={allChecked ?true : isChecked[test.name]}onChange={handleSingleCheck}/>
))}<button onClick={() =>onDelete()}>DELETE</button>
);}
这主要是有效的,除了检查所有.在使用 useState
时,onChange
似乎不会更新.我需要能够选择所有对象或取消选中某些对象以标记为删除.
非常感谢任何帮助.
CodeSandbox 示例:https://codesandbox.io/s/modest-hodgkin-kryco
更新:
好的,在 Richard Matsen 的帮助下,
这是一个没有直接 DOM 操作的新解决方案:
import React, { useState, useEffect } from "react";导入./styles.css";常量数据 = [{名称:测试1",结果:通过"},{名称:测试2",结果:通过"},{名称:test3",结果:通过"},{名称:test4",结果:通过"},{名称:测试5",结果:通过"}];导出默认函数 App() {const [allChecked, setAllChecked] = useState(false);const [isChecked, setIsChecked] = useState();const [loading, setLoading] = useState(true);const [formData, setFormData] = useState(data);const handleAllCheck = e =>{setAllChecked(e.target.checked);};const handleSingleCheck = e =>{setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });};const onDelete = () =>{const itemList = Object.keys(isChecked).map((key:any) => {if (isChecked[key] === true) {返回键}})const 结果 = formData.filter((item:any) => !itemList.includes(item.name))控制台日志(结果)设置表格数据(结果)}useEffect(() => {如果(!加载){setIsChecked(当前 => {const nextIsChecked = {}Object.keys(current).forEach(key => {nextIsChecked[key] = allChecked;})返回 nextIsChecked;});}}, [allChecked, loading]);useEffect(() => {const initialIsChecked = data.reduce((acc,d) => {acc[d.name] = false;返回acc;}, {})setIsChecked(initialIsChecked)设置加载(假)}, [加载])返回 (<div className="应用程序"><div><label>All</label><输入名称=checkall"类型=复选框"已检查={allChecked}onChange={handleAllCheck}/><标签/>
{!加载?formData.map((test, index) => (<div key={index}><label>{test.name}</label><输入类型=复选框"名称={test.name}已检查={isChecked[test.name]}onChange={handleSingleCheck}/>
)): 空值}<button onClick={() =>onDelete()}>DELETE</button>
);}
工作解决方案的代码沙盒:https://codesandbox.io/s/happy-rubin-5zfv3
解决方案
基本问题是 checked={allChecked ?true : isChecked[test.name]}
停止取消检查操作的发生 - 一旦 allChecked
为真,什么值都无关紧要 isChecked[test.name]
有,这个表达式永远是真的.
您应该只依赖 isChecked
作为值,并将更改 allChecked
视为副作用.
useEffect(() => {setIsChecked(当前 => {const nextIsChecked = {}Object.keys(current).forEach(key => {nextIsChecked[key] = allChecked;})返回 nextIsChecked;});}, [allChecked]);...{formData.map((test, index) => (<div key={index}><label>{test.name}</label><输入类型=复选框"名称={test.name}已检查={isChecked[test.name]}onChange={handleSingleCheck}/>))}
还有这个警告出现
<块引用>警告:组件正在更改要控制的复选框类型的不受控制的输入.输入元素不应从不受控制切换到受控制(反之亦然).决定在组件的生命周期内使用受控或非受控输入元素.
所以这基本上是说不要将isChecked
初始化为{}
,因为输入的checked 属性最初是未定义的.改用这个,
{测试1:假,测试2:假,测试3:假,测试4:假,测试5:假,}
或者这样
const data = { ... }const initialIsChecked = data.reduce((acc,d) => {acc[d.name] = false;返回acc;}, {})导出默认函数 App() {const [allChecked, setAllChecked] = useState(false);const [isChecked, setIsChecked] = useState(initialIsChecked);...
I have the following example component that uses multiple checkboxes for choosing what items to remove from a list of objects:
import React, { useState } from "react";
import "./styles.css";
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState({});
const [formData, setFormData] = useState(data);
const handleAllCheck = e => {
setAllChecked(e.target.checked);
};
const handleSingleCheck = e => {
setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });
};
const onDelete = () => {
console.log(isChecked);
const newData = data.filter(
item => !Object.keys(isChecked).includes(item.name)
);
console.log(newData);
setFormData(newData);
};
return (
<div className="App">
<div>
<label>All</label>
<input
name="checkall"
type="checkbox"
checked={allChecked}
onChange={handleAllCheck}
/>
<label />
</div>
{formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={allChecked ? true : isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
))}
<button onClick={() => onDelete()}>DELETE</button>
</div>
);
}
This is mostly working, except for check all. It seems onChange
will not update while using useState
. I need to be able to select all the objects or uncheck some to mark for deletion.
Any help is greatly appreciated.
CodeSandbox Example: https://codesandbox.io/s/modest-hodgkin-kryco
UPDATE:
Okay, after some help from Richard Matsen,
Here is a new solution without direct DOM manipulation:
import React, { useState, useEffect } from "react";
import "./styles.css";
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState();
const [loading, setLoading] = useState(true);
const [formData, setFormData] = useState(data);
const handleAllCheck = e => {
setAllChecked(e.target.checked);
};
const handleSingleCheck = e => {
setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });
};
const onDelete = () => {
const itemList = Object.keys(isChecked).map((key:any) => {
if (isChecked[key] === true) {
return key
}
})
const result = formData.filter((item:any) => !itemList.includes(item.name))
console.log(result)
setFormData(result)
}
useEffect(() => {
if (!loading) {
setIsChecked(current => {
const nextIsChecked = {}
Object.keys(current).forEach(key => {
nextIsChecked[key] = allChecked;
})
return nextIsChecked;
});
}
}, [allChecked, loading]);
useEffect(() => {
const initialIsChecked = data.reduce((acc,d) => {
acc[d.name] = false;
return acc;
}, {})
setIsChecked(initialIsChecked)
setLoading(false)
}, [loading])
return (
<div className="App">
<div>
<label>All</label>
<input
name="checkall"
type="checkbox"
checked={allChecked}
onChange={handleAllCheck}
/>
<label />
</div>
{!loading ? formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
)): null}
<button onClick={() => onDelete()}>DELETE</button>
</div>
);
}
codesandbox of working solution:
https://codesandbox.io/s/happy-rubin-5zfv3
解决方案
The basic problem is checked={allChecked ? true : isChecked[test.name]}
stops the unchecking action from happening - once allChecked
is true it does not matter what value isChecked[test.name]
has, the expression is always going to be true.
You should rely only on isChecked
for the value, and treat changing allChecked
as a side-effect.
useEffect(() => {
setIsChecked(current => {
const nextIsChecked = {}
Object.keys(current).forEach(key => {
nextIsChecked[key] = allChecked;
})
return nextIsChecked;
});
}, [allChecked]);
...
{formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
))}
There's also this warning cropping up
Warning: A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
So that's basically saying don't initialize isChecked
to {}
, because the input's checked property is initially undefined. Use this instead,
{
test1: false,
test2: false,
test3: false,
test4: false,
test5: false,
}
or this way
const data = { ... }
const initialIsChecked = data.reduce((acc,d) => {
acc[d.name] = false;
return acc;
}, {})
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState(initialIsChecked);
...
这篇关于ReactJS:使用 useState 管理多个复选框输入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文