본문 바로가기
Frontend/Zustand

[Zustand] Zustand 맛보기

by Rayched 2025. 6. 24.
목차
1. Zustand란?
_① 상태 관리 라이브러리를 사용해야 하는 이유
_② Zustand 설치 및 기본 예제

1. Zustand란?

 

Zustand는 독일어로 "상태", "형편", "상황"등을 의미하는 단어로

'redux', 'recoil'과 같은 React에서 사용되는 상태 관리 라이브러리 중 하나이다.

 

Zustand는 보일러 플레이트를 사용하지 않기 때문에 코드 작성이 간결하며별도의 Provider 없이도 사용할 수 있다는 장점을 가지고 있는 상태 관리 라이브러리이다.


① 상태 관리 라이브러리를 사용해야 하는 이유

 

Zustand라는 라이브러리가 어떤건지는 대충 알았으나

굳이 Zustand 같은 상태 관리 라이브러리를 써야하는 지에 대해 의문점이 들것이다.

https://dev.to/stuxnat/final-react-project-2poi

기본적으로 React로 개발한 프로젝트는 여러 개의 컴포넌트로 구성되어 있다.

이때 각각의 컴포넌트마다 자기만의 상태, state를 가지고 있으며

자식 컴포넌트에서 부모의 state를 사용하기 위해서는 props를 통해서 전달 받아야 한다.

 

즉, React에서의 데이터는 부모 → 자식으로 단방향으로 전달이 된다.

이러한 구조는 데이터의 흐름이 단순하기 때문에 예측하기 수월하다.

 

다만, 부모에서 자식에게 데이터를 전달하는 과정에서

중간에 껴있는 컴포넌트의 개수가 많다면 어떻게 될까?


Maple To Do Diagram

 

위의 이미지는 필자의 사이드 프로젝트인 Maple To Do의 대략적인 구조도를 가져온 것이다.

해당 구조도를 참고했을 때 데이터의 흐름을 다음과 같이 정리할 수 있다.

Maple To Do 데이터 흐름 정리
1. Mains에서 'category'를 props 통해 자식 컴포넌트인 ToDoList에 전달함.
- category: 사용자가 선택한 category를 기억해두는 용도의 state


2. ToDoList는 부모로부터 전달받은 'category'와 'ToDos'를 자식인 BasedToDo에 전달
- ToDos: 사용자가 추가한 ToDo를 저장하는 배열 state
- props를 통해 전달받은 category는 사용하지 않음

3. BasedToDo에선 자식인 'WeeklyToDo/BossToDo/CustomToDo'에게 'ToDos' 전달
- category의 값에 따라 WeeklyToDo/BossToDo/CustomToDo 중 하나를 랜더링
- props를 통해 전달받은 ToDos는 사용하지 않음

4. WeeklyToDo/BossToDo/CustomToDo에서 ToDos에 전달된 데이터 출력

 

앞에서 제시한 다이어그램과 위의 데이터 흐름 정리 부분을 통해 알 수 있는 것은

'ToDoList'는 부모로부터 받은 데이터인 'category'를 자식인 BasedToDo에게 전달만 하고

'BasedToDo'는 부모로부터 받은 데이터인 'ToDos'를 자식인 WeeklyToDo 외 2개 컴포넌트에게 전달만 한다.

 

여기서 ToDoList와 BasedToDo는 부모 - 자식 간 데이터 전달을 위한 중간 다리 역할을 했다.

 

이런 식으로 props를 하위 컴포넌트로 중첩되게 전달하는 현상을 props drilling이라고 한다.

 

Props Drilling
- 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때
  중간 컴포넌트들을 거쳐야 하는 과정

물론 이러한 Props Drilling 현상은 zustand 같은 상태 관리 라이브러리를 통해 해결할 수 있다.

각 컴포넌트에서 필요한 상태를 구독함으로써, 필요한 데이터만 가져와서 사용할 수 있다.

 

이제 Zustand의 설치법과 기본 예제를 확인해보자.


 

Zustand 설치 및 기본 예제

 

(1). Zustand 설치 및 Store 생성

 

Zustand는 아래 명령어를 입력해서 설치하면 된다. (npm 기준)

npm install zustand

 

 

Zustand에서 전역 상태는 Store라고 지칭하며

이러한 Store는 'create()' 함수를 통해 생성할 수 있다.

 

import {create} from "zustand";

const useCountStore = create((set, get) => ({}));

 

create 함수는 'set'과 'get' 함수를 인자로 받으며

여기서 set()은 상태를 업데이트하는 함수, get()은 상태의 값을 가져오는 함수이다.

 

create 함수는 객체를 반환하는데 해당 객체에는 상태(초기 값)와 액션(함수)을 가지고 있다.

 

더보기

create 함수 관련 추가사항

 

이거는 그냥 개인적으로 호기심이 생겨서 실험해보고 알게된 사실이다.

 

예제 코드에서 'create((set, get) => ({}))'와 같이 작성해서 Store를 생성했는데

만약 'create((set, get) => {})'으로 작성을 하면 어떻게 될까?

 

일단 기본적으로 create(() => {})로 작성했다면

시스템에선 '{ }'를 객체가 아니라 코드 블럭으로 인식을 한다는 건 알고있다.

 

그렇다는 것은 create(() => {})로 작성하면 Error가 발생할까?

결론은 저런 식으로 작성을 해도 최종적으로 반환하는 값이

 

상태(초기값), 액션(함수)를 가지고 있는 객체이면 문제가 생기지 않는다는 것이다.

이는 "객체를 반환한다."라는 전제가 무너지지 않았기 때문에 가능한 일이다.

const useCountStore = create((set) => {
    const Counts = {
        count: 0,
        setCount: () => set((state) => ({count: state.count + 1})
    };
    
    return Counts;
});

 

이렇게 코드를 작성하고, 테스트까지 해본 결과

문제가 발생하지는 않았다.

 

물론 굳이 이렇게 쓸 필요는 없다.

그냥 이건 내 호기심을 해결하기 위해 썼던 방식이기 때문이다.

 

그냥 간단하게 'create(() => ({}))'의 형식으로 작성하는게 더 좋을 것 같다.


 

(2). Zustand 예제 (버튼 클릭 예제)

 

 

//Stores.ts

import {create} from "zustand";

export const useCountStore = create((set) => ({
    Count: 0,
    setCount: () => set((state) => ({state.Count + 1})),
    CountReset: () => set({Count: 0})
}));

 

App.tsx
import {useCountStore} from "stores";

function App(){
    const {Count, setCount, CountReset} = useCountStore();

    return (
        <div>
            <h3>Click Here 👇</h3>
            <button onClick={() => setCount(Count + 1)}>Click me</button>
            <button onClick={() => CountReset()}>Reset</button>
            <h4>버튼 클릭 횟수: {Count}회</h4>
        </div>
    );
};

📔 참고 문헌
- Zustand 공식 문서
- 리액트 취준생을 위한 Zustand 실전 입문 가이드 / 인프런

'Frontend > Zustand' 카테고리의 다른 글

[Zustand] 상태 및 액션 설계 패턴 (작성 중)  (0) 2025.06.25