React

React에서 객체 및 배열 상태 업데이트하기

Mr. Joo 2025. 3. 2. 20:13
728x90

React에서 상태를 다룰 때, 단순한 숫자나 문자열이 아니라 객체(object)나 배열(array) 을 다루는 경우가 많다. 하지만 상태 업데이트를 할 때 직접 수정하면 예상과 다르게 동작할 수 있다.

이번 글에서는 React 공식 문서의 "Updating Objects in State" 및 "Updating Arrays in State" 내용을 기반으로, 객체와 배열 상태를 안전하게 업데이트하는 방법을 정리해본다. -> https://ko.react.dev/learn/managing-state


객체 상태를 직접 수정하면 안 되는 이유

React의 상태는 불변성(immutability) 을 유지해야 한다. 만약 기존 상태 객체를 직접 수정하면, React가 변경을 감지하지 못해 UI가 업데이트되지 않을 수 있다.

잘못된 예시

import { useState } from "react";

function Profile() {
  const [user, setUser] = useState({ name: "John", age: 25 });

  function updateAge() {
    user.age = user.age + 1; // x 상태 직접 변경
    setUser(user);
  }

  return (
    <div>
      <p>이름: {user.name}</p>
      <p>나이: {user.age}</p>
      <button onClick={updateAge}>나이 증가</button>
    </div>
  );
}

위 코드에서 updateAge 함수는 user.age 값을 직접 변경한 후 setUser(user)를 호출하지만, React는 상태가 변경되었다고 인식하지 못한다. 왜냐하면 객체의 참조(reference)가 동일하기 때문이다.


객체 상태를 안전하게 업데이트하는 방법

1. 새로운 객체를 생성하여 업데이트하기

객체 상태를 업데이트할 때는 기존 객체를 직접 수정하지 않고, 새로운 객체를 생성하여 업데이트해야 한다.

function updateAge() {
  setUser({ ...user, age: user.age + 1 });
}

2. 함수형 업데이트 사용하기

React의 상태 업데이트는 비동기적으로 이루어지므로, 최신 상태를 기반으로 변경하려면 함수형 업데이트(functional update) 를 사용하는 것이 좋다.

function updateAge() {
  setUser(prevUser => ({ ...prevUser, age: prevUser.age + 1 }));
}

배열 상태를 직접 수정하면 안 되는 이유

배열도 객체와 마찬가지로 불변성 을 유지해야 한다. 배열을 직접 변경하면 React가 변경을 감지하지 못할 수 있다.

잘못된 예시

function TodoList() {
  const [tasks, setTasks] = useState(["할 일 1", "할 일 2"]);

  function addTask() {
    tasks.push("새로운 할 일"); // x 직접 수정
    setTasks(tasks);
  }

  return (
    <div>
      <ul>{tasks.map((task, index) => <li key={index}>{task}</li>)}</ul>
      <button onClick={addTask}>할 일 추가</button>
    </div>
  );
}

위 코드에서 tasks.push("새로운 할 일")을 사용하면 배열이 직접 변경되지만, setTasks(tasks)를 호출해도 React가 변경을 감지하지 못할 수 있다.


배열 상태를 안전하게 업데이트하는 방법

1. 새로운 배열을 생성하여 업데이트하기

배열을 변경할 때는 기존 배열을 직접 수정하는 대신, 새로운 배열을 생성하여 업데이트해야 한다.

function addTask() {
  setTasks([...tasks, "새로운 할 일"]);
}

배열을 복사한 후 새로운 요소를 추가하면 React가 변경 사항을 감지할 수 있다.

2. 기존 요소 제거하기

배열에서 특정 요소를 삭제하려면 filter를 사용하여 새로운 배열을 만들어야 한다.

function removeTask(taskToRemove) {
  setTasks(tasks.filter(task => task !== taskToRemove));
}

3. 배열의 특정 요소 업데이트하기

배열의 특정 요소를 변경하려면 map을 사용하여 새로운 배열을 만들어야 한다.

function updateTask(oldTask, newTask) {
  setTasks(tasks.map(task => (task === oldTask ? newTask : task)));
}

중첩된 객체 및 배열 상태 업데이트하기

상태로 중첩된 객체(nested object) 또는 배열이 포함된 객체 를 사용하면 더 신중하게 업데이트해야 한다.

const [user, setUser] = useState({
  name: "John",
  tasks: ["할 일 1", "할 일 2"]
});

tasks 배열을 업데이트하려면 아래처럼 처리해야 한다.

function addTask() {
  setUser({ ...user, tasks: [...user.tasks, "새로운 할 일"] });
}

객체와 배열을 함께 관리할 때는 각 레벨에서 새로운 객체나 배열을 생성하는 것이 중요 하다.


정리

  • React 상태는 불변성을 유지해야 한다.
  • 객체 상태를 업데이트할 때 기존 객체를 직접 수정하지 않고, 새로운 객체를 만들어야 한다.
  • 배열 상태도 직접 수정하지 않고, 새로운 배열을 생성하여 업데이트해야 한다.
  • 최신 상태를 반영하려면 함수형 업데이트(functional update) 를 사용하자.
  • 중첩된 객체나 배열을 업데이트할 때는 상위 객체까지 새로운 객체로 만들어야 한다.
  • 요소를 추가할 때는 push() 대신 spread 연산자([...]) 를 사용하자.
  • 요소를 삭제할 때는 filter(), 특정 요소를 변경할 때는 map()을 활용하자.

오늘도 즐코 빡코 !!

728x90
LIST