skip to Main Content

I’m building a small project in React where part of it displays the value of the checked box or boxes.

Project description:

  1. There are 4 checkboxes in total.
  2. Each checkbox represents one of the following colors: Red, Blue, Green and Yellow.
  3. All checkboxes are unchecked from the start.
  4. When a checkbox is checked, it will display the corresponding value to the page in text form.
  5. If multiple boxes are checked, the value of all the checked boxes will be displayed to the page.
  6. Unchecking a checkbox also removes the corresponding value from the page.

How it should work:

  1. User checks the Red box.
  2. The text “Red” appears on the page.
  3. User checks the Blue and Green box.
  4. The text “Red, Blue, Green” appears on the page.
  5. User unchecks the Blue box.
  6. The text “Blue” disappears and only “Red, Green” remains.

My solution:

  1. I’m using Set() to add or delete values, depending on whether the checkbox is disabled or not, using if/else statement.

  2. After that I convert Set() to a string with a comma as a separator and assign it to the variable checkedColor.

  3. 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


  1. Chosen as BEST ANSWER

    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:

    let set = new Set();
        
    function MyApp() {
      const [color, setColor] = useState();
    
      const handleCheck = event => {
        setColor([]);
        if(event.target.checked) {
          set.add(event.target.value);
        } 
        else {
          set.delete(event.target.value); 
        }
        setColor(Array.from(set).join(', '));
      }
      return (<div>...</div>);
    }
    

    A huge thanks to P O and moonwave99 for their guidance.


  2. 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 of set 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>

    Login or Signup to reply.
  3. 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:

    export default function App() {
      const [colors, setColors] = useState([]);
    
      const handleCheck = (event) => {
        const color = event.target.value;
        setColors((prev) =>
          event.target.checked ? [...prev, color] : prev.filter((x) => x !== color)
        );
      };
    
      return (
        <div>
          ...
          <p>Checked color(s): {colors.join(", ")}</p>
        </div>
      );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search