我将带有属性的复选框字段的列表传递给我的组件,我想根据人员的选择更改checked
属性的值,但是我最大能做的就是将数组。
如何在我的状态下更改此特定密钥?
这是我的代码:
export default function Combocheck({ data, title, id }) {
const inputLabel = React.useRef(null);
const [state, setState] = React.useState({
checkbox: data.map((element) => {
element.checked = false;
return element;
})
});
const changeState = name => event => {
const newValue = !state.checkbox[name].checked;
setState({ checkbox: [
...state.checkbox,
state.checkbox[name] = {
...state.checkbox[name],
checked: newValue
}
]
});
}
console.log(state);
return (
<div>
<Typography color='textSecondary'>{title}</Typography>
<Divider />
<FormGroup>
{state.checkbox.map(({code, description, checked}, i) => {
return <FormControlLabel control={
<Checkbox
key={code}
checked={checked}
onChange={changeState(i)}
value={code}
color="primary"
/>
}
key={code}
label={description}
/>
})}
</FormGroup>
</div>
);
}
可以在此处查看或编辑:https://stackblitz.com/edit/react-irhqw9?file=Hello.js
答案 0 :(得分:3)
每次更新状态时,您都会添加一个复选框项!相反,请考虑在您的元素上进行映射,并仅更改适用的元素:
const changeState = name => event => {
setState({
checkbox: state.checkbox.map((checkbox, i) => {
return i !== name ?
checkbox :
{ ...checkbox, checked: !checkbox.checked }
})
});
}
我也不喜欢使用元素索引作为名称;我很确定您可以使用该代码(假设它是唯一的)就可以了,那么这不必是高阶函数:
const changeState = event => {
setState({
checkbox: state.checkbox.map((checkbox) => {
return event.target.value !== checkbox.code ?
checkbox :
{ ...checkbox, checked: !checkbox.checked }
})
});
}
,然后在Checkbox
道具中:
onChange={changeState}
答案 1 :(得分:1)
我更喜欢为每个复选框使用一个useState函数。
在挂钩之前的“过去”时代,每个组件只有一个状态-setState
函数会将状态与传递给setState
的对象合并。 Hooks和useState并非那样。一个组件中可以有许多useState挂钩,并且状态不会合并。
有些代码可以粘贴到使用create-react-app创建的App.js中,以显示我的意思:
App.js
import React, { useState } from 'react';
function App() {
var [ firstCheckbox, setFirstCheckbox ] = useState(true); // true - first check box defaults to checked.
var [ secondCheckbox, setSecondCheckbox ] = useState(false); // false = second check box defaults to un-checked.
return (
<div style={{display:'flex', flexDirection: 'column'}}>
<label for='first-check-box'><input type="checkbox" checked={firstCheckbox} onChange={() => setFirstCheckbox(!firstCheckbox)}></input>First Check Box</label>
<label for='second-check-box'><input type="checkbox" checked={secondCheckbox} onChange={() => setSecondCheckbox(!secondCheckbox)}></input>Second Check Box</label>
</div>
);
}
export default App;
另一个使chrome开发人员工具更有用的提示:
当您按照我的建议使用许多useState挂钩时,很难看到哪个状态挂钩是哪个。每个useState挂钩仅显示为useState: true
,没有任何标签。下面的代码通过将实际状态设为对象的属性,并在chrome开发人员工具中显示标签,来标识开发人员工具的“组件”标签中的useState钩子。
App.js:
import React, { useState } from 'react';
function App() {
var [ firstCheckbox, setFirstCheckbox ] = useState({firstCheckBox: true});
var [ secondCheckbox, setSecondCheckbox ] = useState({secondCheckBox: false});
return (
<div style={{display:'flex', flexDirection: 'column'}}>
<label htmlFor='first-check-box'>
<input type="checkbox"
checked={firstCheckbox.firstCheckBox}
onChange={() => setFirstCheckbox(
{firstCheckBox: !firstCheckbox.firstCheckBox}
)}>
</input>
First Check Box
</label>
<label htmlFor='second-check-box'>
<input
type="checkbox"
checked={secondCheckbox.secondCheckBox}
onChange={() => setSecondCheckbox(
{secondCheckBox: !secondCheckbox.secondCheckBox}
)}>
</input>
Second Check Box
</label>
</div>
);
}
export default App;
为了清楚起见,我在上面使用了输入元素的onChange事件。这要求用户单击实际的复选框。我更愿意允许他们单击标签或复选框上的任何位置。为此,我们可以使用label元素的onClick事件:
为了避免在控制台中抱怨输入不是控制器,我也将它们标记为readOnly。
App.js:
import React, { useState } from 'react';
function App() {
var [ firstCheckbox, setFirstCheckbox ] = useState({firstCheckBox: true});
var [ secondCheckbox, setSecondCheckbox ] = useState({secondCheckBox: false});
return (
<div style={{display:'flex', flexDirection: 'column'}}>
<label
htmlFor='first-check-box'
onClick={() => setFirstCheckbox({firstCheckBox: !firstCheckbox.firstCheckBox})}>
<input type="checkbox" checked={firstCheckbox.firstCheckBox} readOnly/>
First Check Box
</label>
<label
htmlFor='second-check-box'
onClick={() => setSecondCheckbox({secondCheckBox: !secondCheckbox.secondCheckBox})}>
<input type="checkbox" checked={secondCheckbox.secondCheckBox} readOnly/>
Second Check Box
</label>
</div>
);
}
export default App;