Skip to content

[Refactor] Zustand Store 내부 구현 리팩토링 #357

@kyeoungwoon

Description

@kyeoungwoon

📝 리팩토링 이유

코드 리팩토링이 필요한 이유와 목적을 상세히 작성해주세요.
(예: 가독성 향상, 구조 분리, 성능 개선 등)

성능 면에서 actions를 객체로 구분하는 것이 아니라 일일히 전개해서 구현하는게 좋다고 합니다. (by 잼민이)


아래 글을 참고하세요

네, actions를 밖으로 빼는 것이 **필수 규칙은 아니지만, 그렇게 하는 것이 Zustand를 훨씬 더 효율적이고 깔끔하게 사용하는 모범 사례(Best Practice)**이기 때문입니다.

가장 큰 이유는 불필요한 리렌더링을 막아 성능을 최적화하고, 스토어의 구조를 명확하게 만들기 위함입니다.


## 1. 성능 최적화 (가장 중요한 이유) 🚀

컴포넌트가 스토어의 state는 필요 없고, 오직 action 함수만 필요한 경우가 많습니다. 예를 들어, 사용자가 클릭하는 버튼은 login()이나 addItem() 같은 함수만 호출할 뿐, user 정보나 items 배열을 화면에 직접 보여주지는 않을 수 있습니다.

actions가 중첩된 경우:

// 컴포넌트에서 actions 객체 전체를 구독
const { addItem } = useCartStore((state) => state.actions);

이 방식은 actions 객체 자체가 변하지 않으므로 괜찮아 보이지만, 만약 다른 컴포넌트가 items 배열을 변경하면 state 객체 자체가 새로 만들어지므로, 이 컴포넌트도 불필요하게 리렌더링될 수 있습니다.

actions를 밖으로 뺀 경우:

// addItem 함수 하나만 정확히 구독
const addItem = useCartStore((state) => state.addItem);

이렇게 하면, 스토어의 다른 상태 값(items 배열 등)이 아무리 많이 변경되어도, addItem 함수 자체는 변하지 않으므로 이 컴포넌트는 전혀 리렌더링되지 않습니다. 이는 특히 규모가 큰 애플리케이션에서 상당한 성능 이점을 가져옵니다.

useShallow를 사용해 actions 객체만 선택할 수도 있지만, 액션을 개별적으로 분리하는 것이 더 명확하고 효과적입니다.


## 2. 스토어 구조의 명확성 🧠

stateactions를 명시적으로 분리하면 스토어의 구조가 한눈에 들어옵니다.

  • State: 이 스토어가 어떤 데이터를 가지고 있는가? (명사)
  • Actions: 이 스토어가 어떤 행동을 할 수 있는가? (동사)

이렇게 역할을 나누면 스토어의 책임이 명확해져 코드를 이해하고 유지보수하기가 훨씬 쉬워집니다.


## 3. get() 함수 사용 가능

이전 질문에서 경험하셨듯이, 한 액션이 다른 상태 값에 접근해야 할 때(get() 함수 사용) actions가 중첩된 구조에서는 구현이 까다롭거나 불가능합니다.

// actions를 밖으로 빼야만 get()을 쉽게 사용할 수 있음
immer((set, get) => ({
  questions: [],
  getQuestionIdByIndex: (index) => {
    // get()을 통해 questions 상태에 접근
    return get().questions[index].id;
  },
  //...
}))

액션들을 최상위 레벨에 두는 것이 get()set()을 자유롭게 활용하는 Zustand의 표준 패턴입니다.

결론적으로, actions를 밖으로 빼는 것은 필수는 아니지만 성능 최적화, 코드 가독성, 스토어 기능 확장이라는 세 마리 토끼를 모두 잡을 수 있는 매우 효과적인 방법이므로 강력하게 권장됩니다.


작업 내용

(여기에 리팩토링 내용을 작성해주세요.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    ♻️ Refactor코드 구조 개선사용자 경험은 동일하지만 내부 코드 구조 또는 품질을 개선 예: 컴포넌트 분리, 로직 최적화

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions