Zustand Library Document - dev-team-projects/DeliTalk GitHub Wiki

์ž‘์„ฑ์ž : ์ž„์„ฑ์ค€, ์ •ํ˜œ์˜, ์ด์œค์„œ


Zustand

Zustand๋ฅผ ๋“ค์–ด๊ฐ€๊ธฐ ์ „์—..

Redux ๋ฐฉ์‹

actions.js

export const INIT_CHARACTER = 'INIT_CHARACTER';
export const MAIN_CHARACTER = 'MAIN_CHARACTER';
export const MAIN_CHARACTER_DEPT = 'MAIN_CHARACTER_DEPT';

// Action Creator ํ•จ์ˆ˜
export const initChar = () => ({
  type: INIT_CHARACTER,
});
export const mainChar = (newPosition) => ({
  type: MAIN_CHARACTER,
  payload: newPosition,
});
export const mainCharDept = (newPosition) => ({
  type: MAIN_CHARACTER_DEPT,
  payload: newPosition,
});
  • type์€ ์ง€์ •๋œ ํ•„์ˆ˜ ์†์„ฑ์ด์ง€๋งŒ payload๋Š” ์ง€์ •๋œ ์†์„ฑ์ด ์•„๋‹™๋‹ˆ๋‹ค.(๊ด€ํ–‰)

reducer.js

import {
  INIT_CHARACTER,
  MAIN_CHARACTER,
  MAIN_CHARACTER_DEPT,
} from '../actions/actions';

const initialState = {
  name: '',
  currentPosition: [280, 0, -355],
  deptInitPosition: [0, 0, 0],
};

export function mainCharReducer(state = initialState, action) {
  switch (action.type) {
    case INIT_CHARACTER:
      return {
        ...state,
        name: '',
        currentPosition: [280, 0, -355],
        deptInitPosition: [0, 0, 0],
      };
    case MAIN_CHARACTER:
      // console.log('action.payload', action.payload)
      return {
        ...state,
        name: 'SJ',
        currentPosition: action.payload,
        deptInitPosition: state.deptInitPosition,
      };
    case MAIN_CHARACTER_DEPT:
      return {
        ...state,
        name: 'SJ',
        currentPosition: state.currentPosition,
        deptInitPosition: action.payload,
      };
    default:
      return state;
  }
}

store.js

import { createStore } from 'redux';
import rootReducer from '../reducers/rootReducer';

// ์Šคํ† ์–ด ์ •์˜
const store = createStore(rootReducer);

export default store;

rootReducer.js

import { combineReducers } from 'redux';
import { mainCharReducer } from './mainCharReducer';
// ...

// ๋ชจ๋“  ๋ฆฌ๋“€์„œ ๊ฒฐํ•ฉ - ์„ฑ์ค€
const rootReducer = combineReducers({
  mChar: mainCharReducer,
  // ...
});

export default rootReducer;

App.jsx

<Provider store={store}>
  <BrowserRouter>{/* ... */}</BrowserRouter>
</Provider>

์ƒํƒœ ๊ตฌ๋…

const myChar = useSelector((state) => state.mChar);
//...

useEffect(() => {
  dispatch(mainChar(targetPosition));
}, [targetPosition]);

Recoil ๋ฐฉ์‹

atom.js

import { atom } from 'recoil';

export const isStartScene = atom({
  key: 'isStart',
  default: false,
});

jsx

// ...
const setStart = useSetRecoilState(isStartScene);
//...

return (
  <motion.group
    onAnimationComplete={() => setStart(true)}
    {/* ... */}
  >
    <Text3D
      {...fontStyle}
    >
      Hello Seong Jun
      <meshNormalMaterial />
    </Text3D>
    {/* ... */}
  </motion.group>;
)
// ...
const isStart = useRecoilValue(isStartScene)

return (
  {isStart && <Car />}
  // ...
)

Zustand

store.js

// ...

// ์ดˆ๊ธฐ ์ƒํƒœ
const initialState = {
  keyword: '',
  checkIn: formatDate(checkInDate),
  checkOut: formatDate(checkOutDate),
  tripDay: 1,
  numberOfPeople: 2,
};

export const useAccomSearchStore = create(
  persist(
    (set, get) => ({
      initialState,
      setKeywordState: (value) => set({ keyword: value }),
      setCheckInState: (date) => set({ checkIn: date }),
      setCheckOutState: (date) => set({ checkOut: date }),
      setTripDayState: (day) => set({ tripDay: day }),
      setNumberOfPeople: (count) =>
        set({ numberOfPeople: count === 1 ? 2 : count }),
      resetState: () => set(initialState),
    }),
    {
      name: 'accomSearchStore',
      getStorage: () => localStorage,
      partialize: (state) => ({
        keyword: state.keyword,
        checkIn: state.checkIn,
        checkOut: state.checkOut,
        tripDay: state.tripDay,
        numberOfPeople: state.numberOfPeople,
      }),
    }
  )
);

jsx

const state = useAccomSearchStore((state) => state);

// or

const { checkIn, checkOut, tripDay } = useAccomSearchStore((state) => state);
const { setCheckInState, setCheckOutState, setTripDayState, resetState } =
  useAccomSearchStore((state) => state);


Redux, Recoil ๋“ฑ ์—ฌ๋Ÿฌ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ๋Š”๋ฐ ์™œ Zustand์ธ๊ฐ€

์—ฌ๋Ÿฌ ์ƒํƒœ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋น„๊ตํ•ด๋ดค์„ ๋•Œ Zustand๊ฐ€ ํ›จ์”ฌ ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค.

Redux

  • ๊ฐ•๋ ฅํ•˜์ง€๋งŒ ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.
  • ์„ค์ •์ด ๋ณต์žกํ•ด ์ดˆ๋ฐ˜ ์ง„์ž… ์žฅ๋ฒฝ์ด ๋†’์Šต๋‹ˆ๋‹ค.

Recoil

  • Recoil์€ React ์ „์šฉ์ด๊ณ  ์•„ํ†ฐ ๊ธฐ๋ฐ˜์˜ ๊ด€๋ฆฌ ๋ฐฉ์‹์ด ์ง๊ด€์ ์ž…๋‹ˆ๋‹ค.
    • useRecoilState, useRecoilValue ๊ฐ™์€ ํ›…์„ ํ†ตํ•ด atom์„ ์ง์ ‘ ๊ฐ€์ ธ์˜ค๊ณ  ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.
    • props drilling์ด ํ•„์š” ์—†๊ณ , API ์‚ฌ์šฉ ๋ฐฉ์‹์ด React์˜ useState์™€ ๊ฑฐ์˜ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.
      const [text, setText] = useRecoilState(textState);
  • ๊ณต์‹์ ์œผ๋กœ Recoil์€ SSR์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • Recoil์€ ๊ธฐ๋ณธ์ ์œผ๋กœ CSR์ž…๋‹ˆ๋‹ค.
  • ์ปค๋ฎค๋‹ˆํ‹ฐ ๊ทœ๋ชจ๊ฐ€ ์•„์ง ์ž‘๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ React + Spring Boot ์กฐํ•ฉ์ผ ๊ฒฝ์šฐ CSR ๋ฐฉ์‹์ด๋ฏ€๋กœ Recoil์„ ์‚ฌ์šฉํ•ด๋„ ๋ฌด๋ฐฉํ•ฉ๋‹ˆ๋‹ค.

Zustand

  • Redux์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ํ›จ์”ฌ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.

    • ์ฝ”๋“œ๋Ÿ‰์ด ์ ๊ณ  ์„ค์ •์ด ๊ฐ„ํŽธํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฆฌ๋ Œ๋”๋ง ์ตœ์ ํ™”, ๋น„๋™๊ธฐ ์ง€์›, ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ์—ฐ๋™, ๋ฏธ๋“ค์›จ์–ด ํ™•์žฅ ๋“ฑ ์‹ค๋ฌด์—์„œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์„ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • useStore ํ›…์„ ํ†ตํ•ด ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ๊ตฌ๋…ํ•˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์„ฑ๋Šฅ ๋ฉด์—์„œ๋„ ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

ํ™•์žฅ์„ฑ๊ณผ ์ƒ์‚ฐ์„ฑ์„ ๋ชจ๋‘ ๊ณ ๋ คํ•  ๊ฒฝ์šฐ Zustand๊ฐ€ ๋” ๋‚ซ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ ์˜ˆ์‹œ

  • ํ…Œ๋งˆ ์„ค์ •
  • ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์ •๋ณด
  • ๋ชจ๋‹ฌ ์ƒํƒœ
  • ๋“ฑ๋“ฑ..

Zustand๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‹จ์ˆœํ•˜๊ณ  ์„ฑ๋Šฅ๋ฉด์—์„œ ํšจ์œจ์ ์ธ์ง€

  • Zustand์˜ ๊ฐ€์žฅ ํฐ ๋งค๋ ฅ์€ ๋‹จ์ˆœํ•œ API์™€ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์ด๋Š” ์„ฑ๋Šฅ ์ตœ์ ํ™”์— ์žˆ์Šต๋‹ˆ๋‹ค.

    • ๋‹จ์ˆœํ•œ API

      ์ „์—ญ ์ƒํƒœ๋ฅผ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ ์–ธํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ„๋„์˜ Provider๋‚˜ ๋ณต์žกํ•œ boilerplate ์ฝ”๋“œ๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.

    • ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง ์ตœ์†Œํ™”

      ์„ ํƒ์  ๊ตฌ๋…(Selector)์„ ํ†ตํ•ด ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ๊ตฌ๋…ํ•  ์ˆ˜ ์žˆ๊ณ , ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๊ด€๋ จ๋œ ์ปดํฌ๋„ŒํŠธ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค.

  • Redux๋Š” ์ƒํƒœ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด action, reducer, dispatch๋ฅผ ์ •์˜ํ•˜๊ณ  ์—ฐ๊ฒฐํ•ด์•ผ ํ•˜๋Š” ๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๊ฐ€ ๋งŽ์ง€๋งŒ, Zustand๋Š” ๋‹จ์ง€ ํ•˜๋‚˜์˜ create ํ•จ์ˆ˜๋กœ ์ƒํƒœ์™€ ๋กœ์ง์„ ๋ชจ๋‘ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

  • ๊ทธ๋ฆฌ๊ณ  ์„ฑ๋Šฅ ๋ฉด์—์„œ๋Š”, Redux๋‚˜ Context API๋Š” ์ƒํƒœ๊ฐ€ ๋ฐ”๋€Œ๋ฉด ํ•ด๋‹น ์ƒํƒœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋Š” ๋ฐ˜๋ฉด, Zustand๋Š” useStore(selector)๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ•„์š”ํ•œ ์ƒํƒœ๋งŒ ๊ตฌ๋…ํ•˜๊ณ  ๊ทธ ์™ธ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š์•„ ๋ถˆํ•„์š”ํ•œ ๋ Œ๋”๋ง์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ