React

[React] Zustand란?

yo09 2025. 1. 10. 10:05

Zustand란?

Zustand는 독일어로 "상태"라는 뜻으로, 리액트 상태 관리를 간단하고 효율적으로 할 수 있게 도와주는 라이브러리이다. 상태(state)를 더 직관적이고 깔끔하게 관리할 수 있도록 설계되었다.


왜 Zustand를 사용할까?

리액트에서 기본적으로 제공하는 useState와 useReducer를 사용해도 상태 관리는 충분히 가능하다. 하지만 다음과 같은 경우, Zustand가 더 좋은 대안이 될 수 있다.

1. 상태가 복잡해질 때

  • 프로젝트가 커질수록 상태가 여기저기 분산되어 관리하기 어려워진다.
  • 여러 컴포넌트에서 동일한 상태를 공유하거나, 상호작용해야 할 때는 props를 계속 전달해야 해서 코드가 복잡해진다.
  • Zustand는 중앙 저장소(store)를 만들어 상태를 한 곳에서 관리하고, 필요한 컴포넌트가 그 상태를 가져다 쓰게 해줍니다.

2. props로 상태를 계속 전달해야 할 때

  • 리액트에서는 부모에서 자식 컴포넌트로 상태를 내려주기 위해 props를 사용한다.
  • 하지만, 컴포넌트가 많아지면 props를 계속 전달하는 작업이 반복되어 코드가 복잡해지고 가독성이 떨어집니다. 이를 "props drilling"이라고 한다.
  • Zustand는 상태를 중앙에서 관리하기 때문에 props drilling 문제를 깔끔하게 해결한다.

3. Redux처럼 복잡한 설정이 싫을 때

  • Redux도 상태 관리 라이브러리지만, 설정 과정이 복잡하고 코드가 길어질 수 있다.
  • Zustand는 설치와 사용이 간단하며, 몇 줄의 코드로 상태를 관리할 수 있다.

기존 리액트 상태 관리와 Zustand 비교

  리액트 (useState) Zustand
설정 별도 설치 없이 바로 사용 가능 라이브러리 설치 필요
상태 공유 props를 통해 부모에서 자식으로 전달 여러 컴포넌트에서 바로 상태 접근 가능
코드 복잡도 컴포넌트 간 상태 전달이 많아 복잡할 수 있음 상태 접근이 직관적이고 코드가 간단
복잡한 상태 관리 상태가 많아지면 비효율적일 수 있음 복잡한 상태도 중앙에서 쉽게 관리 가능
학습 곡선 쉬움 쉬움 (Redux보다 훨씬 간단)

Zustand를 언제 사용할까?

  • 여러 컴포넌트에서 동일한 상태를 사용해야 할 때
    예) 로그인 상태, 쇼핑몰 장바구니 데이터, 공통 설정 정보 등
  • props로 상태를 여러 단계 전달하는 게 번거로울 때
    예) 부모-자식-손자 컴포넌트로 계속 props를 전달해야 하는 경우
  • Redux는 너무 복잡하다고 느낄 때
    예) 작은 프로젝트나 간단한 상태 관리가 필요한 경우
  • 리액트 상태 관리를 더 간단히 하고 싶을 때

Zustand 사용법

1. 설치

Zustand는 NPM 명령어로 간단히 설치할 수 있다.

npm install zustand

2. Store 만들기

Zustand에서 상태는 store(저장소)에 정의한다.
예를 들어, 메모를 작성하는 기능을 만든다고 가정해보겠다.

// stores/memos.js
import create from 'zustand';

const useMemosStore = create((set) => ({
  memo: '', // 하나의 메모 상태
  setMemo: (text) => set({ memo: text }), // 메모 상태 업데이트 함수

  memos: [], // 모든 메모를 저장할 배열 상태
  setMemos: (newMemo) =>
    set((prev) => ({
      memos: [...prev.memos, newMemo], // 기존 메모에 새로운 메모 추가
    })),
}));

export default useMemosStore;

3. Store 사용하기

만들어진 상태를 컴포넌트에서 가져와 사용한다.

메모 작성 폼 컴포넌트

// components/Form.js
import useMemosStore from '../stores/memos';

const Form = () => {
  const { memo, setMemo, setMemos } = useMemosStore();

  const handleWriteMemo = (e) => {
    setMemo(e.target.value); // 입력값을 memo에 저장
  };

  const handleAddMemo = (e) => {
    e.preventDefault();
    setMemos(memo); // 메모를 추가
    setMemo(''); // 입력창 초기화
  };

  return (
    <form onSubmit={handleAddMemo}>
      <input type="text" value={memo} onChange={handleWriteMemo} />
      <button type="submit">메모 추가</button>
    </form>
  );
};

메모 리스트 컴포넌트

// components/Memos.js
import useMemosStore from '../stores/memos';

const Memos = () => {
  const { memos } = useMemosStore();

  return (
    <ul>
      {memos.map((memo, index) => (
        <li key={index}>{memo}</li>
      ))}
    </ul>
  );
};

4. App.js에서 상태 삭제

Zustand로 상태를 관리하기 때문에, App.js에서는 더 이상 상태를 정의하거나 전달할 필요가 없다.

 
// App.js
import Form from './components/Form';
import Memos from './components/Memos';

function App() {
  return (
    <div>
      <h1>Zustand 메모 앱</h1>
      <Form />
      <Memos />
    </div>
  );
}

export default App;