1

So i've been working on this for awhile what i'm trying to do is change a checked value on checkbox click.

My initial state looks like this:

const [todoList, setTodoList] = useState({
    foundation: {
      steps: [
        { key: "1", title: "setup virtual office", isDone: false },
        { key: "2", title: "set mission and vision", isDone: false },
        { key: "3", title: "select business name", isDone: false },
        { key: "4", title: "buy domain", isDone: false },
      ],
    },

    discovery: {
      steps: [
        { key: "1", title: "create roadmap", isDone: false },
        { key: "2", title: "competitor analysis", isDone: false },
      ],
    }
  });

and my map and onClick function (updateCheckFoundation works when click the checkbox)

    {todoList.foundation.steps.map((item) => {
        return (
          <div>
            <input type="checkbox" defaultChecked={item.isDone}
             onClick={(event)=> updateCheckFoundation({
                 isDone:event.target.checked, 
                 key:item.key
                 })}/>
            <span>{item.title}</span>
          </div>
        );
      })}

so how can ı update todoList use setState?

my code (updateCheckFoundation func.) like this and is not working :( :

const updateCheckFoundation = ({isDone, key}) => {
    const updateTodoList = todoList.foundation.steps.map((todo)=> {
     if(todo.key === key){
      return {
        ...todo,
        isDone
      };
    }
    return todo;

    });
    setTodoList(updateTodoList);
 

  }

1 Answer 1

3

Issue

Your updateCheckFoundation callback isn't maintaining the state invariant, and is in fact, dropping all but the foundation.steps array of state.

const updateCheckFoundation = ({isDone, key}) => {
  const updateTodoList = todoList.foundation.steps.map((todo)=> {
    if(todo.key === key){
      return {
        ...todo,
        isDone
      };
    }
    return todo;

  });
  setTodoList(updateTodoList); // <-- only the state.foundation.steps array!!
}

Solution

In function components, when using the useState state updater functions you need to handle merging state (the root state), and nested state, yourself, manually.

const updateCheckFoundation = ({ isDone, key }) => {
  setTodoList(state => ({
    ...state, // <-- shallow copy state object
    foundation: {
      ...state.foundation, // <-- shallow copy
      steps: state.foundation.steps.map(todo => todo.key === key
        ? { ...todo, isDone }
        : todo)
    },
  }));
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.