Don't Update State Directly In React
Tags: react
Published: 2022-10-05 11:15:54

In this post, we will discuss how to update state in correct way 

first, App.js that contain list of todos and pass them as props to Todos component, after this we receive props in Todos component and passing them as props to Todo component to render every todo in list of todos, in Todos.js there is handleToggleComplete to make checkbox marked or not and contain handleSelect to detect which todo is selected 

App.js code :

```
import Todos from "./Todos";

export default function App() {
 
  const initialTodos = [
    {
      id : 1 ,
      complete : false ,
      name : 'first todo'
    } , 
    {
      id : 2 ,
      complete : true ,
      name : 'second todo'
    } ,
    {
      id : 3 ,
      complete : false ,
      name : 'third todo'
    }
  ]
  return (
    <div className="App">
     <Todos initialTodos = {initialTodos} />  
    </div>
  );
}

```

Todos.js code : 

```
import React, { useState } from "react";
import Todo from "./Todo";

const Todos = ({ initialTodos }) => {
  const [todos, setTodos] = useState(initialTodos);
  const [selectedTodo, setSelectedTodo] = useState();

  const handleToggleComplete = (todoId) => {
    setTodos((currTodos) => {
      const todo = currTodos.find((todo) => todo.id === todoId);
      todo.complete = !todo.complete;
      return currTodos;
    });
  };

  const handleSelect = (todoId) => {
    setSelectedTodo(todos.find((todo) => todo.id === todoId));
  };

  return (
    <>
      {todos.map((todo) => (
        <Todo
          key={todo.id}
          todo={todo}
          handleToggleComplete={handleToggleComplete}
          handleSelect={handleSelect}
        />
      ))}
      <h3>Selected Todo</h3>

      {selectedTodo && (
        <Todo
          todo={selectedTodo}
          handleToggleComplete={handleToggleComplete}
          handleSelect={handleSelect}
        />
      )}
    </>
  );
};

export default Todos;

```

Todo.js code : 

```
import React from "react";

const Todo = ({ todo, handleToggleComplete, handleSelect }) => {
  const toggleComplete = () => {
    handleToggleComplete(todo.id);
  };

  const onSelect = () => {
    handleSelect(todo.id);
  };
  return (
    <div>
      <input
        type="checkbox"
        checked={todo.complete}
        onChange={toggleComplete}
      />
      {todo.name}
      <button onClick={onSelect}>Select</button>
    </div>
  );
};

export default Todo;

```

now let's see the result of this code 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rs9dptliuaujbystp7hb.gif)

as we see we can't update any checkbox, this because we update state directly, in setTodos we update currTodos directly and return currTodos 

```
 const handleToggleComplete = (todoId) => {
    setTodos((currTodos) => {
      const todo = currTodos.find((todo) => todo.id === todoId);
      todo.complete = !todo.complete;
      return currTodos;
    });
  };
```

to solve this problem we can update state by take copy of currTodos and update through copied state

```
const handleToggleComplete = (todoId) => {
    setTodos((currTodos) => {
      const copy = [...currTodos]
      return copy.map(todo => {
        if(todo.id === todoId) {
          return {...todo  , complete : !todo.complete}
        }
        return todo 
      })
    });
  };

```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7begn3gtfhm0hfjsm4on.gif)

to make more clarification about how to update state in code above,
1- copy is array we make update through it 
2- if there is update return {...todo  , complete : !todo.complete} this will be updated in copy array 
3- if there is no update return todo 
4- all this array (copy array) will be returned as new state as we say setTodos(copy) 

```
 return copy.map(todo => {
        if(todo.id === todoId) {
          return {...todo  , complete : !todo.complete}
        }
        return todo 
      })
```

let's see the result now : 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vf9t38af8vplijcwc9od.gif)

now we can update state of each checkbox successfully, but let's see what about the selectedTodo :


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pxtfg98qxzj31tfgii0r.gif)

as we see, we selected third todo, but when mark or unmark checkbox from third todo it didn't update on selectedTodo that is becuase we stored the derived state of selectedTodo

in this code below the wrong is we store derived state, so keep in mind don't store derived state 
`setSelectedTodo(todos.find((todo) => todo.id === todoId))
`

the correct way is using this line of code below so every re-render we calculate updated selectedTodo and we can using useMemo for this
`const selectedTodo = todos.find(todo => todo.id === selectedTodoId)`

and that is the code below in Todos.js with all changes 

```
import React, { useState } from "react";
import Todo from "./Todo";

const Todos = ({ initialTodos }) => {
  const [todos, setTodos] = useState(initialTodos);
  const [selectedTodoId, setSelectedTodoId] = useState();

  const selectedTodo = todos.find(todo => todo.id === selectedTodoId)

  const handleToggleComplete = (todoId) => {
    setTodos((currTodos) => {
      const copy = [...currTodos]
      return copy.map(todo => {
        if(todo.id === todoId) {
          return {...todo  , complete : !todo.complete}
        }
        return todo 
      })
    });
  };

  return (
    <>
      {todos.map((todo) => (
        <Todo
          key={todo.id}
          todo={todo}
          handleToggleComplete={handleToggleComplete}
          handleSelect={setSelectedTodoId}
        />
      ))}
      <h3>Selected Todo</h3>

      {selectedTodo && (
        <Todo
          todo={selectedTodo}
          handleToggleComplete={handleToggleComplete}
          handleSelect={setSelectedTodoId}
        />
      )}
    </>
  );
};

export default Todos;

```


let's see the result now of this code : 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m1yhybv3h9lchsnpho3t.gif)

That is all about how to update state in correct way, keep in mind always not update state directly, take copy of state and update through the copied state 


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gu3z6njekusfuet3ajf7.gif)
Thanks for your time to read this post