skip to Main Content

Have a Todo App.
Whenever i will click on check it should only trigger handleCheck() for that particular element of Div(Array Elements)

It is triggering handleCheck() in all the div(Array Elements).

 const todoData = [
        
        {id:0,todoname:"Study",todotoday:"Completing CSS today"},
        {id:1,todoname:"Coding",todotoday:"Leetcode 2 Problems"}
    ];

    const [myArray,setmyArray] = useState(todoData);
    const [isChecked, setIsChecked] = useState();

 const handleCheck = (id) =>{
        console.log(id);
      setIsChecked(current => !current);
    }
 return (
 <div className="todomain">
    {
 myArray.map((obj)=>{
          return ( <div className="todobox" key={obj.id} style={{opacity:isChecked ? 0 : ''}}>
          <div className="checkcont">
           <img src={check} alt="Check" className='chkbtn btn' onClick={() => handleCheck(obj.id)}/>
          </div>
            <h2 className="head" >Todo: {obj.todoname}</h2>
            <h3 className="todocont">{obj.todotoday}</h3>
            <div className="todoboxbtn">
             <TodoIcon />
            </div>
            </div> )
        })
      }
</div>
   )

2

Answers


  1. Because there’s a difference between "one thing" and "many things".

    This state represents many things (an array):

    const [myArray,setmyArray] = useState(todoData);
    

    But this state represents one thing (a single value):

    const [isChecked, setIsChecked] = useState();
    

    So, when isChecked is true, which element of myArray does it apply to? Currently your options are "all of them" or "none of them".

    Instead of just storing a boolean value, perhaps you meant to store the id value? For example:

    const [checkedItem, setCheckedItem] = useState();
    
    const handleCheck = (id) =>{
      console.log(id);
      setCheckedItem(id);
    }
    

    Then checkedItem would contain the id of the one "item" which is currently checked. You’d then compare that id in the code to conditionally style your elements:

    <div
      className="todobox"
      key={obj.id}
      style={{ opacity: (checkedItem === obj.id) ? 0 : '' }}
    >
    

    Alternatively, if you want to track "checked items" as "many things" then that would be an array. For example:

    const [checkedItems, setCheckedItems] = useState([]);
    

    Checking/unchecking items would be a matter of adding/removing items in that array. For example:

    const handleCheck = (id) =>{
      console.log(id);
      if (checkedItems.includes(id)) {
        setCheckedItems(checkedItems.filter(i => i !== id));
      } else {
        setCheckedItems([...checkedItems, id]);
      }
    }
    

    And the condition in the JSX markup would be checking if that array contains the obj.id value (rather than is the obj.id value). For example:

    <div
      className="todobox"
      key={obj.id}
      style={{ opacity: checkedItems.includes(obj.id) ? 0 : '' }}
    >
    
    Login or Signup to reply.
  2. In order to make this code work properly you should add isChecked property to your data and modify the way you update your state.

    You final code will look like this:

      const todoData = [
        {
          id: 0,
          todoname: 'Study',
          todotoday: 'Completing CSS today',
          isChecked: false, // new boolean property
        },
        {
          id: 1,
          todoname: 'Coding',
          todotoday: 'Leetcode 2 Problems',
          isChecked: false, // new boolean property
        },
      ]
    
      const [myArray, setMyArray] = useState(todoData)
    
      /**
       * Given obj id, map all items inside MyArray. If obj.id was found, update it's
       * isChecked property. Finally use setMyArray to update the state and re-render UI
       * @param {Number} id the id of a certain obj in MyArray
       */
      const toggleTodoCheck = (id) => {
        const updatedMyArray = myArray.map((obj) => {
          if (obj.id === id) return { ...obj, isChecked: !obj.isChecked }
          return obj
        })
        setMyArray(updatedMyArray)
      }
      return (
        <div className="todomain">
          {myArray.map((obj) => {
            return (
              <div
                className="todobox"
                key={obj.id}
                style={{ opacity: obj.isChecked ? 0 : '' }}
              >
                <div className="checkcont">
                  <img
                    src={check}
                    alt="Check"
                    className="chkbtn btn"
                    onClick={() => toggleTodoCheck(obj.id)}
                  />
                </div>
                <h2 className="head">Todo: {obj.todoname}</h2>
                <h3 className="todocont">{obj.todotoday}</h3>
                <div className="todoboxbtn">
                  <TodoIcon />
                </div>
              </div>
            )
          })}
        </div>
      )
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search