Flux 패턴과 zustand

웅재·2023년 2월 7일
0
post-thumbnail

flux 패턴이란?

어디서 어느 방향으로 데이터가 전달될지 알지 못할 정도로 혼란한 MVC 패턴의 복잡성을 해소하기 위해, Flux 패턴에서는 데이터가 한 방향으로만 흐르도록 했다. Flux는 간단하게 설명하면 어떤 Action이 발생하면, Dispatcher에서 이를 받아와 해석한 후 Store에서 저장된 정보에 변경을 가하고, 그 결과가 View로 다시 전달되도록 한다. 이를 다음과 같은 그림으로 나타낼 수 있다.

하지만 사용자가 View를 통해서 클릭 같은 액션을 발생시킬 수 있기때문에 이를 고려하면 다음과 같은 흐름으로 나타낼 수 있다.

Action

데이터를 변경하는 행위로서 Dispactcher에게 전달되는 객체

Dispatcher

모든 데이터의 흐름을 관리하는 중앙 허브

Store

상태 저장소로서 상태와 상태를 변경할 수 있는 메서드를 가지고 있음

View

React Component

Redux의 단점

Redux는 전역 상태를 관리하기 위한 정말 좋은 솔루션이지만, 너무 많은 코드를 작성해야한다. 아주 간단한 예시를 적기 위해서라도 많은 코드를 적고, 또 그 코드를 이해하는 것은 너무 어렵다.

zustand

Redux와 마찬가지로 Flux 패턴을 따르는 상태관리 라이브러리

장점

  • store 구현 방식 및 변경 방식이 간단해 보일러플레이트 코드가 매우 줄어든다.
  • 익히기가 굉장히 쉽다.
  • Provider로 감쌀 필요가 없다.
  • context 방식보다 리렌더링이 줄어든다.

example

// CountStore.ts
import { create } from 'zustand';

interface countState {
  count: number;
  addCount: () => void;
  resetCount: () => void;
}

export const useCountStore = create<countState>((set) => ({
  count: 0,

  addCount: () => set((state) => ({ count: state.count + 1 })),
  resetCount: () => set({ count: 0 }),
}));

count 라는 초기값을 선언하고 그 값을 조작할 수 있는 action addCountresetCount를 선언합니다.

// example.tsx
import { useCountStore } from 'src/stores/CountStore';

export default function Example() {
  const { count, addCount, resetCount } = useCountStore();

  return (
    <>
      <div>{count}</div>
      <button onClick={addCount}>클릭</button>
      <button onClick={resetCount}>리셋</button>
    </>
  );
}

store에서 생성한 useCountStore를 불러와서 구조 분해 할당을 통해 쉽게 사용할 수 있다.
버튼 클릭 시 count가 늘어나고 초기화 되는 것을 확인할 수 있다.

devtools를 통해 상태 Debugging

zustand 는 Middleware로 devtools를 지원하고 있다. Redux Devtools를 설치하면 크롬 개발자 도구에서 Redux Devtools를 확인할 수 있다.

import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

interface countState {
  count: number;
  addCount: () => void;
  resetCount: () => void;
}

export const useCountStore = create<countState>()(
  devtools((set) => ({
    count: 0,

    addCount: () => set((state) => ({ count: state.count + 1 })),
    resetCount: () => set({ count: 0 }),
  }))
);

create안에 devtools를 연결하는 방법으로 쉽게 사용할 수 있다.

최적화

custom hook만 export하기

장점

  • 불필요한 리렌더링 방지
  • 더 깨끗한 인터페이스 제공
  • 모든 곳에서 셀렉터를 반복적으로 작성할 필요가 없음
  • 실수로 전체 스토어를 구독하는 것을 방지
import { create } from 'zustand';
import { devtools } from 'zustand/middleware';

interface countState {
  count: number;
  actions: {
    addCount: () => void;
    resetCount: () => void;
  };
}

const useCountStore = create<countState>()(
  devtools((set) => ({
    count: 0,

    actions: {
      addCount: () => set((state) => ({ count: state.count + 1 })),
      resetCount: () => set({ count: 0 }),
    },
  }))
);

export const useCount = () => useCountStore((state) => state.count);
export const useCountActions = () => useCountStore((state) => state.actions);
  const count = useCount();
  const { addCount, resetCount } = useCountActions();

action은 절대 변하지 않기 때문에 전부를 구독해도 리렌더링에 영향을 주지 않음

zustand와 react query를 같이 사용하는 방법
[React] Flux 패턴에 대해서: Redux와 Zustand
Web: React Flux 패턴

0개의 댓글