Home > Software design >  Implement dynamic checkbox with checked handler in React js
Implement dynamic checkbox with checked handler in React js

Time:04-04

I'm having problems setting state for my dynamic checkbox for my array, changing an object from false to true, using a checked handler.

below is my code:

const [form, setForm] = useState({
    tags:[
     { name: "Athletic/Higher caloric", isChecked: false },
     { name: "Aggressive Weight Loss", isChecked: false },
     { name: "Quick and Easy", isChecked: false } ]})

const onCheckedHandler = (index) => {
      const updatedTags = 
        form.tags.map((tag, i) => {
           if (index === i) {
             form.tags[i].isChecked = !form.tags[i].isChecked;
             } 
           return { tag }; 
        }); 

    setForm(updatedTags);


return (
   {form.tags.map((tag, i) => (
        <div>
        <label>{tag.name}</label> 
        <input 
           type="checkbox"
           checked={tag.isChecked}
           onChange={(event) => onCheckedHandler(i)}
           key={i} /> 
        </div>
       ))})

I get this error: "Uncaught TypeError: Cannot read properties of undefined (reading 'map') at Create (line:107)"

But line 107 is just the start of another map function that works and is totally unrelated. What am I doing wrong? I tried avoiding mutating the isChecked value directly in the object with an if statement. Maybe it's how I setState?

CodePudding user response:

It is my understanding that:

  • Initial state is an object const [form, setForm] = useState({...});
  • This has a prop named tags.
  • But, the variable updatedTags (in the handler-method) is an array. It's not an object.
  • So, setForm(updatedTags) will set form to be an array which will not have any prop named tags

Consequently, please try changing the handler like so:

const onCheckedHandler = (index) => {
  setForm(prev => ({
    ...prev,
    tags: [
      ...prev?.tags?.map(
        ({isChecked, ...rest}, idx) => (
          idx === index
          ? {...rest, isChecked: !isChecked}
          : {...rest, isChecked}
        )
      )
    ]
  }));
};

Also, please use checks before attempting map on the return as well. May be try something like so:

form?.tags?.map(...)

OR

form && form.tags && Array.isArray(form.tags) && form.tags.map(...)

CodePudding user response:

The problem comes probably from here:

return (
   {form.tags.map((tag, i) => (
        <div>
        <label>{tag.name}</label> 
        <input 
           type="checkbox"
           checked={tag.isChecked}
           onChange={(event) => onCheckedHandler(i)}
           key={i} /> 
        </div>))}
)

The issue is you're trying to render using the form state which at the time of mounting (of the component) is probably undefined. As your error says cannot read property of undefined, reading map it probably refers to that form.tags is undefined and can't read map of it.

A good idea is to check before rendering if what you're trying to render is defined or not. For example:

return (
   {form.tags ? form.tags.map((tag, i) => (
        <div>
        <label>{tag.name}</label> 
        <input 
           type="checkbox"
           checked={tag.isChecked}
           onChange={(event) => onCheckedHandler(i)}
           key={i} /> 
        </div>)) : <div>Loading</div>}
)
  • Related