I’m building a small project in React where part of it displays the value of the checked box or boxes.
Project description:
- There are 4 checkboxes in total.
- Each checkbox represents one of the following colors: Red, Blue, Green and Yellow.
- All checkboxes are unchecked from the start.
- When a checkbox is checked, it will display the corresponding value to the page in text form.
- If multiple boxes are checked, the value of all the checked boxes will be displayed to the page.
- Unchecking a checkbox also removes the corresponding value from the page.
How it should work:
- User checks the Red box.
- The text “Red” appears on the page.
- User checks the Blue and Green box.
- The text “Red, Blue, Green” appears on the page.
- User unchecks the Blue box.
- The text “Blue” disappears and only “Red, Green” remains.
My solution:
-
I’m using Set() to add or delete values, depending on whether the checkbox is disabled or not, using if/else statement.
-
After that I convert Set() to a string with a comma as a separator and assign it to the variable checkedColor.
-
Finally I assign checkedColor to setColor();
Expected result: A string of text is displayed in real-time onto the page with the value of the checked boxes. Unchecking a box removes the corresponding value from the string.
Current result: A string of text with the value of latest checkbox only is displayed onto the page in real-time. Unhecking the latest checkbox results in an empty string.
Question: Any ideas what’s causing the unexpected result? And what’s the solution?
Here is the code:
function MyApp() {
const [color, setColor] = useState();
let set = new Set();
let checkedColor;
const handleCheck = event => {
if(event.target.checked) {
set.add(event.target.value);
}
else {
set.delete(event.target.value);
}
checkedColor = [...set].join(', '); //convert to a string
setColor(checkedColor);
console.log(checkedColor); //behaves corretly when checkedColor is NOT assigned to setColor
}
return (
<div>
<input type="checkbox" id="red" name="color" value="red" onChange={handleCheck}/>
<label htmlFor="color">Red</label> <br />
<input type="checkbox" id="blue" name="color" value="blue" onChange={handleCheck}/>
<label htmlFor="color">Blue</label> <br />
<input type="checkbox" id="green" name="color" value="green" onChange={handleCheck}/>
<label htmlFor="color">Green</label> <br />
<input type="checkbox" id="yellow" name="color" value="yellow" onChange={handleCheck}/>
<label htmlFor="color">yellow</label> <br />
<p>Checked color(s): {color}</p>
</div>
);
}
I tried checking the value of checkedColor using console.log and to my surprise it displayed and updated the string of text just as intended. But when I assign checkedColor to setColor, it no longer behaves as intended.
3
Answers
I figured it out!
I removed the variable checkedColor and made the set variable global. I assign an empty array to setColor when the function handleCheck is called. Then I assign the new updated string to setColor.
Here is the working code:
A huge thanks to P O and moonwave99 for their guidance.
My suspicion is that because the
set
is not a state variable it is getting reset on every render. Meaning when you call setColor it will set it to the value ofset
and then re-render. When it re-renders,set
is re-initialized to empty. This is why it works without setColor.You could instead just store the colors as a list, have logic to check for uniqueness in your handleClick, and then display as
<p>Checked color(s): {color.join(", ")}</p>
Variables defined inside react components are instantiated again between renders, so your set will be empty on every click.
You can use a simple array like: