如何使用反应钩子实现多个复选框
Posted
技术标签:
【中文标题】如何使用反应钩子实现多个复选框【英文标题】:How to implement multiple checkbox using react hook 【发布时间】:2019-10-09 21:35:02 【问题描述】:我想使用 react-hook 在我的 html 页面上实现多个复选框。
我尝试使用此 URL 实现:https://medium.com/@Zh0uzi/my-concerns-with-react-hooks-6afda0acc672。在提供的链接中,它是使用类组件完成的并且工作正常,但是每当我使用 React hook setCheckedItems 更新复选框选中状态时,它都不会重新渲染视图。
第一次渲染视图并从 Checkbox 组件打印 console.log()。单击复选框功能后,handleChange 被调用并 checkedItems 更新值,但视图不再呈现(没有 console.log() 打印)。并且 checkedItems.get("check-box-1") 也没有打印任何值。
下面是我的示例代码。
复选框示例:
import React, useState from 'react';
import Checkbox from '../helper/Checkbox';
const CheckboxExample = () =>
const [checkedItems, setCheckedItems] = useState(new Map());
const handleChange = (event) =>
setCheckedItems(checkedItems => checkedItems.set(event.target.name, event.target.checked));
console.log("checkedItems: ", checkedItems);
const checkboxes = [
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
,
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
];
return (
<div>
<lable>Checked item name : checkedItems.get("check-box-1") </lable> <br/>
checkboxes.map(item => (
<label key=item.key>
item.name
<Checkbox name=item.name checked=checkedItems.get(item.name) onChange=handleChange />
</label>
))
</div>
);
export default Example;
复选框:
import React from 'react';
const Checkbox = ( type = 'checkbox', name, checked = false, onChange ) =>
console.log("Checkbox: ", name, checked);
return (<input type=type name=name checked=checked onChange=onChange /> )
export default Checkbox;
【问题讨论】:
【参考方案1】:我不认为使用Map
来代表状态是最好的主意。
我已经使用普通的Object
实现了您的示例,并且可以正常工作:
https://codesandbox.io/s/react-hooks-usestate-xzvq5
const CheckboxExample = () =>
const [checkedItems, setCheckedItems] = useState(); //plain object as state
const handleChange = (event) =>
// updating an object instead of a Map
setCheckedItems(...checkedItems, [event.target.name] : event.target.checked );
useEffect(() =>
console.log("checkedItems: ", checkedItems);
, [checkedItems]);
const checkboxes = [
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
,
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
];
return (
<div>
<lable>Checked item name : checkedItems["check-box-1"] </lable> <br/>
checkboxes.map(item => (
<label key=item.key>
item.name
<Checkbox name=item.name checked=checkedItems[item.name] onChange=handleChange />
</label>
))
</div>
);
编辑:
原来Map
可以用作状态值,但要触发重新渲染,您需要用新的 Map 替换而不是简单地改变它,这不是 React 选择的,即:
const handleChange = (event) =>
// mutate the current Map
checkedItems.set(event.target.name, event.target.checked)
// update the state by creating a new Map
setCheckedItems(new Map(checkedItems) );
console.log("checkedItems: ", checkedItems);
但在这种情况下,我认为使用 Map 没有任何好处,除了使用 .get()
和 .set()
而不是 x[y]
的更简洁的语法。
【讨论】:
这会启动他的渲染吗?看起来他正在使用 checkedItems 状态变量进行渲染,但他的代码看起来只是在更新 setCheckedItems 状态变量。不过我可能会误解它 @abelito 如果您运行链接的演示,您将清楚地看到checked
属性对应于状态,即 ckeckbox 显示为已选中以响应状态更新。
啊,我现在看到了,太好了!
@pawel 感谢您的快速回复。使用这个有效的对象。我想知道为什么它不能使用 Map。
@Nakesh 这可能与 React 内部有关。我确定Map
和Set
在 Redux 商店中使用时效果不佳,这就是我从这个角度解决您的问题的原因。不确定是否有官方消息称不应在 React 组件状态下使用它们,但看看差异,在您的情况下 Map over Object 似乎没有任何好处。【参考方案2】:
看起来有点长,但是如果您将地图展开并将其应用于new Map
,您的组件将重新渲染。我认为使用 Object 引用而不是 Map
在这里效果最好。
const useState = React
const Mapper = () =>
const [map, setMap] = useState(new Map());
const addToMap = () =>
const RNDM = Math.random().toFixed(5)
map.set(`foo$RNDM`, `bar$RNDM`);
setMap(new Map([...map]));
return (
<div>
<ul>
[...map].map(([v, k]) => (
<li key=k>
k : v
</li>
))
</ul>
<button onClick=addToMap>add to map</button>
</div>
);
;
const rootElement = document.getElementById("react");
ReactDOM.render(<Mapper />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
【讨论】:
【参考方案3】:作为使用单个对象来保存多个项目状态的补充,如果在单个渲染中更新多个项目,更新将不会按预期发生。渲染周期内更新的提交将简单覆盖之前的提交。
解决方案是将所有更改集中在一个对象中并一次性提交,如下所示:
// An object that will hold multiple states
const [myStates, setMyStates] = useState();
// An object that will batch all the desired updates
const statesUpdates = ;
// Set all the updates...
statesUpdates[state1] = true;
statesUpdates[state2] = false;
// etc...
// Create a new state object and commit it
setMyStates(Object.assign(, myStates, statesUpdates));
【讨论】:
可以,或者使用函数更新状态:reactjs.org/docs/hooks-reference.html#functional-updates【参考方案4】:作为Map
的替代方案,您可以考虑使用Set
。然后您不必担心最初将每个项目设置为false
以表示未选中。快速 POC:
const [selectedItems, setSelectedItems] = useState(new Set())
function handleCheckboxChange(itemKey: string)
// first, make a copy of the original set rather than mutating the original
const newSelectedItems = new Set(selectedItems)
if (!newSelectedItems.has(itemKey))
newSelectedItems.add(itemKey)
else
newSelectedItems.delete(itemKey)
setSelectedItems(newSelectedItems)
...
<input
type="checkbox"
checked=selectedItems.has(item.key)
onChange=() => handleCheckboxChange(item.key)
/>
【讨论】:
【参考方案5】:
export default function Input(props)
const
name,
isChecked,
onChange,
index,
= props;
return (
<>
<input
className="popup-cookie__input"
id=name
type="checkbox"
name=name
checked=isChecked
onChange=onChange
data-action=index
/>
<label htmlFor=name className="popup-cookie__label">name</label>
</>
);
const checkboxesList = [
name: 'essential', isChecked: true,
name: 'statistics', isChecked: false,
name: 'advertising', isChecked: false,
];
export default function CheckboxesList()
const [checkedItems, setCheckedItems] = useState(checkboxesList);
const handleChange = (event) =>
const newCheckboxes = [...checkedItems];
newCheckboxes[event.target.dataset.action].isChecked = event.target.checked;
setCheckedItems(newCheckboxes);
console.log('checkedItems: ', checkedItems);
;
return (
<ul className="popup-cookie-checkbox-list">
checkboxesList.map((checkbox, index) => (
<li className="popup-cookie-checkbox-list__item" key=checkbox.name>
<Input
id=checkbox.name
name=checkbox.name
isChecked=checkbox.isChecked
onChange=handleChange
index=index
/>
</li>
))
</ul>
);
```
【讨论】:
以上是关于如何使用反应钩子实现多个复选框的主要内容,如果未能解决你的问题,请参考以下文章