숨참고 개발다이브

[React / React Native] use-immer 란? 본문

개발/React & React Native

[React / React Native] use-immer 란?

사라 Sarah 2024. 2. 18. 17:52
728x90

 

https://github.com/immerjs/use-immer

 

GitHub - immerjs/use-immer: Use immer to drive state with a React hooks

Use immer to drive state with a React hooks. Contribute to immerjs/use-immer development by creating an account on GitHub.

github.com

A hook to use immer as a React hook to manipulate state.

⇒ immer 라이브러리를 기반으로 만들어진 React 환경에서 상태 관리를 할 수 있는 훅이다.

 

 

특징

 

use-immer의 특징은 다음과 같다.

 

  1. 복잡한 상태 업데이트: 상태가 복잡하고 중첩된 객체나 배열을 포함하는 경우, 일반적인 상태 업데이트 로직을 작성하기가 까다로울 수 있다. 이 경우 useImmer를 사용하여 더 간단하고 가독성 있는 코드를 작성할 수 있다.
  2. 불변성 유지: React에서 상태를 업데이트할 때는 불변성을 유지해야 한다. Immer를 사용하면 불변성을 유지하면서도 마치 가변 객체를 직접 수정하는 것처럼 상태를 업데이트할 수 있다.
  3. 컴포넌트의 상태 업데이트 성능 최적화: Immer는 내부적으로 변경 사항을 추적하고 필요한 경우에만 실제로 새로운 상태를 생성한다. 이는 React 컴포넌트의 불필요한 리렌더링을 방지하고 상태 업데이트의 성능을 최적화할 수 있다.

 

use-Immer의 특징인 ‘컴포넌트 상태 업데이트 최적화’에 대한 자세한 내용이 궁금해 GPT에게 질문해 보았다.

 

Object에 대해서 useState를 사용할 때는 object의 어떤 속성이 변경되어도 전체 상태 객체를 새로운 것으로 간주해 object를 사용하는 모든 컴포넌트를 리렌더링 한다.

하지만 useImmer는 object의 'A'라는 속성을 변경하면 변경된 부분을 추적해 'object.A'에 한해서만 업데이트하고 컴포넌트를 렌더링 한다. 따라서 불필요한 렌더링을 방지할 수 있게 된다.

 

 

설치 방법
npm install immer use-immer

 

 

사용법
import React, { useState } from 'react';
import { useImmer } from 'use-immer';

function ExampleComponent() {
  const [state, setState] = useImmer({ count: 0 });

  const increment = () => {
    setState(draft => {
      draft.count += 1;
    });
  };

  const decrement = () => {
    setState(draft => {
      draft.count -= 1;
    });
  };

  return (
    <View>
      <Text>{state.count}</Text>
      <Button title="+" onPress={increment} />
      <Button title="-" onPress={decrement} />
    </View>
  );
}

 

위 코드에서는 useImmer를 사용하여 상태를 선언하고, increment 함수와 decrement 함수를 만들어 상태를 변경한다.

상태를 변경할 때 draft라는 매개 변수를 받아서 새로운 상태를 반환한다. draft는 변경될 수 있는 가상의 상태로, 변경 작업을 직접 수행한다.

 

 

예제

 

자세한 예제 코드는 다음과 같다. TODO 리스트를 관리하고 TODO를 추가하는 기능을 구현한 예제 코드이다.

import React, { useRef } from "react";
import { useImmer } from "use-immer";

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

const TodoList = () => {
  const inputRef = useRef<HTMLInputElement>(null);

  // useImmer를 사용하여 초기 상태를 생성
  const [todos, updateTodos] = useImmer<Todo[]>([]);

  // todo를 추가하는 함수
  const addTodo = (text?: string) => {
    if (!text) return;

    updateTodos((draft) => {
      // 새로운 todo 객체를 생성하고 배열에 추가
      draft.push({ id: Math.random(), text: text, completed: false });
    });
  };

  return (
    <div>
      <h1>Todo List</h1>
      <ul>
        {/* todos 배열을 매핑하여 각각의 todo 아이템을 렌더링 */}
        {todos.map((todo: Todo) => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
      {/* todo를 추가하는 버튼과 입력 필드 */}
      <input ref={inputRef} type="text" placeholder="Add todo" />
      <button onClick={() => addTodo(inputRef?.current?.value)}>
        Add Todo
      </button>
    </div>
  );
};

export default TodoList;

 

예제 코드를 실행하면 다음과 같은 결과를 얻을 수 있다.

 

300x250
Comments