Post

24/05/21 React useState hook의 batch update

목적

리액트에서, setState() 를 여러번 사용해서 작업을 처리하려고 했더니 한 번만 적용이 되길래 찾아보았다.

batch update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const App = () => {
  const [count, setCount] = useState(0);
  // const handleCountPlus = () => {
  //   setCount((state) => state + 1);
  // };

  return (
    <>
      <div>{count}</div>
      {/* <button onClick={handleCountPlus}>클릭</button> */}
      <button
        onClick={() => {
          setCount(count + 1);
          setCount(count + 1);
          setCount(count + 1);
          console.log(`count: ${count}`);
          setCount((prev) => prev + 1);
          setCount((prev) => prev + 1);
          setCount((prev) => prev + 1);
          console.log(`count: ${count}`);
        }}
      >
        클릭
      </button>
    </>
  );
};

위 코드를 작성했는데, 먼저 내가 예상한 결과는 console.log() 에는 3 씩 증가하면서 count 가 표현될 줄 알았으나, 0이 출력되었다. 그리고 count 가 증가하는 차이는 6씩 증가할 것이라 생각했다. 하지만, 클릭 한 번에 4씩 증가했다.

그래서 찾아보니, setState() 는 비동기로 동작한다는 사실을 알았다. 그러니 console.log() 가 갱신 전의 state 를 출력할 수 밖에 없지!

다음으로는, 왜 6이 아니고 4씩 증가했느냐였다. 주석을 하나 씩 처리하면서 확인해보니, 함수 형태로 사용할 때만 setState 를 여러 번 호출하는 것이 가능했다. 일반적으로, 리액트가 setState 를 처리할 때 효율성을 위해 상태가 변한 것들을 한 번에 갱신을 시키기 때문이란다. setCount(count + 1)` 처럼 작성했을 경우에는 여러 번 작성하면 동일한 행동을 단 한 번만 적용하도록 바꿔서 생기는 현상이라는 것을 알았다.

그러나, 함수 형태로 작성하면 매 번 업데이트가 가능했다. 또한, 함수 형태로 작성을 하니 setState 로 기존의 state 에도 접근이 가능한 것을 알았다.

이를 통해, 자식 컴포넌트에 state 를 전달할 때도 응용할 수 있었다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// TodoContainer.jsx

const [toDos, setToDos] = useState(initialState);
// ToDoForm 컴포넌트에서 제어함.

const workingToDos = toDos.filter((toDo) => !toDo.isDone);
const doneToDos = toDos.filter((toDo) => toDo.isDone);

return (
  <>
    <h2>My To Do List</h2>
    <ToDoForm setToDos={setToDos} /> {/*   부분 */}
    <ToDoList title="Working" toDos={workingToDos} setToDos={setToDos} />
    {/* isDone === true */}
    <ToDoList title="Done!" toDos={doneToDos} setToDos={setToDos} />
    {/* isDone === false */}
  </>
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// TodoForm.jsx

const [title, setTitle] = useState("");
const [content, setContent] = useState("");

const onSubmit = (evt) => {
  if (!title || !content) {
    Swal.fire({
      title: "이런..",
      text: "빈 칸을 모두 채워주세요!",
      icon: "error"
    });
  }

  evt.preventDefault();

  setTitle("");
  setContent("");

  const nextToDo = {
    id: uuidv4(),
    title,
    content,
    isDone: false
  };

  setToDos((toDo) => [...toDo, nextToDo]);
  {
    /* ⭐ 이 부분 */
  }
  setTitle("");
  setContent("");
};

부모 컴포넌트인 TodoContainer.jsx 에서 자식 컴포넌트인 TodoForm.jsx 으로 setState 만을 props 로 내려보내 상태 변경을 한 예시다.

앞으로 알아가야할 게 많아진다~~~

This post is licensed under CC BY 4.0 by the author.