[英]How do I Map several controlled input checkboxes from an array in React?
我正在嘗試從這樣的數組中制作一些受控復選框
const subjects = [
{
name: 'WebDev',
label: 'Web Development',
},
{
name: 'GraphicDesign',
label: 'Graphic Design',
},
{
name: 'Engineering',
label: 'Engineering',
},
];
我想讓它們受控,所以對於選中的屬性,我需要它由 state 控制。 但是我如何遍歷它們並每次訪問 state 中的正確 object ? 我想我也許可以解析 subject.name 字符串,但這肯定不是好習慣嗎? 事實上,我也許可以在索引匹配的 state 中創建一個匹配的數組,但我不認為這是可擴展的並且嚴重依賴於正確的順序。
{subjects.map((subject, i) => (
<div className="w-full sm:w-auto" key={i}>
<label className="flex content-center p-3">
<input type="checkbox" name={subject.name} value={subject.name} onChange={onInputChange} checked={????}/>
<span className="ml-3">{subject.label}</span>
</label>
</div>
))}
我也有其他類似的輸入。 對於他們來說,這很容易,因為我可以使用state.name
來控制他們。
<input id="name" type="text" value={state.name} onChange={onInputChange} name="name" required/>
然后我使用廣義 function 來更新輸入。 這需要使用useState()
Hook
const onInputChange = e => {
const item = e.target.name;
const value = e.target.type === "checkbox" ? e.target.checked : e.target.value;
setState({
...state,
[item]: value,
})
}
React 中處理此類問題的最佳實踐是什么? 如果我可以在我的 state 中包含主題,如下所示,那就太好了。
我是否應該放棄單獨的數組並包含 state 中的所有信息?
const [state, setState] = useState({
name:'',
email: '',
message: '',
checkedSubs: {
WebDev: false,
GraphicDesign: false,
Engineering: false
},
emailSent: false
})
謝謝!
使用多個狀態來跟蹤受試者的 state 和您的一般數據。 給每個主題一個名為check
的額外屬性,它應該包含一個 boolean 值。 該值將確定復選框的選中 state。
在onInputChange
function 中,使用新檢查的輸入 state 更新subjects
state。
添加一個具有依賴關系的useEffect
掛鈎: subjects
數組。 每當subjects
的值發生變化時,都會觸發useEffect
回調 function 內部的邏輯。 在該 function 中,根據subjects
數組中的值更新您的常規 state。
最終結果將是subjects
數組將確定您的輸入。 每當更改輸入時, subjects
state 都會更新。 然后當subjects
發生變化時,輸入將被重新渲染, data
中的值將根據變化進行更新。
const ExampleComponent = () => {
const [ subjects, setSubjects ] = useState([
{
name: 'WebDev',
label: 'Web Development',
checked: false
},
{
name: 'GraphicDesign',
label: 'Graphic Design',
checked: false
},
{
name: 'Engineering',
label: 'Engineering',
checked: false
},
]);
const [ data, setData ] = useState({
name:'',
email: '',
message: '',
checkedSubs: {
WebDev: false,
GraphicDesign: false,
Engineering: false
},
emailSent: false
});
const onInputChange = e => {
const item = e.target.name;
const isChecked = e.target.checked;
const updatedSubjects = subjects.map(subject => {
if (subject.name === item) {
return {
...subject,
checked: isChecked
}
}
return subject;
});
setSubjects(updatedSubjects);
};
useEffect(() => {
setData({
...data,
checkedSubs: subjects.reduce((acc, cur) => {
acc[cur.name] = cur.checked;
return acc;
}, {})
});
}, [subjects]);
return (
subjects.map(({ name, label, checked }, i) => (
<div className="w-full sm:w-auto" key={i}>
<label className="flex content-center p-3">
<input type="checkbox" name={name} value={name} onChange={onInputChange} checked={checked}/>
<span className="ml-3">{label}</span>
</label>
</div>
))
)
}
onInputChange
您當前的onInputChange
處理程序根據input
的name
屬性更新state
中的屬性。 實現這一點的最簡單方法之一是讓此處理程序像更新任何其他字段一樣更新復選框。
這意味着您的主題將成為state
的頂級屬性。 只要主題名稱不可能與"email"
類的表單字段相同,就可以了。 您可以將state
重新排列成其他變量。
您可以將 map 轉換為您的示例格式:
// can't use variable subjects because it's already defined
const {name, email, message, emailSent, ...subjectBooleans} = state;
const formatted = {name, email, message, emailSent, subjects: subjectBooleans}
您只能獲取包含已檢查主題名稱的數組:
const checkedSubjects = subjects
.filter(o => state[o.name])
.map( o => o.name );
我不確定subjects
數組的來源以及它是常量還是可能會改變的東西。 您可以從初始 state 中省略這些屬性,並假設undefined
意味着false
/ unchecked。 我們通過查看state[subject.name]
來查看是否檢查了一個主題,我們可以使用!!
顯式轉換為boolean
更好地處理這種undefined
的情況。
const MyForm = ({ subjects }) => {
// removed initial values for subjects
// you could set these, but they aren't required
const [state, setState] = useState({
name: "",
email: "",
message: "",
emailSent: false
});
// no changes to this function
const onInputChange = (e) => {
const item = e.target.name;
const value =
e.target.type === "checkbox" ? e.target.checked : e.target.value;
setState({
...state,
[item]: value
});
};
return (
<form>
<input
id="name"
type="text"
value={state.name}
onChange={onInputChange}
name="name"
required
/>
{/* ... other inputs ... */}
{subjects.map((subject, i) => (
<div className="w-full sm:w-auto" key={i}>
<label className="flex content-center p-3">
<input
type="checkbox"
name={subject.name}
value={subject.name}
onChange={onInputChange}
checked={!!state[subject.name]}
/>
<span className="ml-3">{subject.label}</span>
</label>
</div>
))}
</form>
);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.