I want to implement multiple checkboxes on my HTML page using react-hook.
I tried implementing using this URL: https://medium.com/@Zh0uzi/my-concerns-with-react-hooks-6afda0acc672. In the provided link it is done using class component and working perfectly but whenever I am using React hook setCheckedItems to update checkbox checked status it's not re-rendering the view.
The very first time the view is rendering and console.log() is printing from Checkbox component. After clicking on checkbox function handleChange gets called and checkedItems updates the value but the view is not rendering again (no console.log() printing). And {checkedItems.get("check-box-1")} is also not printing any value.
Below is my sample code.
CheckboxExample :
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;
Checkbox:
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;
The state can be changed by providing the new state value or an updater function. The updater function takes the current state and returns the new state. The state related to a checkbox input is a boolean. When the state is false the checkbox is unchecked, when the state is true the checkbox is checked.
I don't think using a Map
to represent the state is the best idea.
I have implemented your example using a plain Object
and it works:
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>
);
}
EDIT:
Turns out a Map
can work as the state value, but to trigger a re-render you need to replace the Map with a new one instead of simply mutating it, which is not picked by React, i.e.:
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);
}
but in this case, I think there is no benefit to using a Map other than maybe cleaner syntax with .get()
and .set()
instead of x[y]
.
Seems a bit of a long way round but if you spread the map out and apply it to a new Map
your component will re-render. I think using a Object reference instead of a Map
would work best here.
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With