상태관리 라이브러리 사용후기

최환석·2023년 5월 23일
1
post-thumbnail

서론

우리는 상태를 관리하기 위해서 기타 라이브러리의 힘을 빌리거나 직접 그 기능을 구현하기도 한다. 하지만 먼저 우리가 왜 써야하는지 부터 알아야 한다. 라이브러리를 도입하는 것은 좋으나 항상 합당한 이유와 함께 같이 쓰는 것이 좋기 때문이다.

우리가 왜 상태관리를 하게 되는가?

먼저 근본적인 질문이다. 우리는 왜 상태관리를 하게 될까? 그 이유는 크게 두가지가 있다. 먼저 한 사이트에 대해서 다크모드를 구현한다고 가정해보자.

먼저 다크모드를 구현하기 위해서는 하나의 상태를 만들어 보자

export default function DarkMod() {
  const [dark, setDark] = useState(false);

  return (
    <button onClick={() => {setDark((prev) => !prev)}}>
      {dark ? 'Light' : 'Dark'}
    </button>
  );
}
}

먼저 위와 같은 컴포넌트를 만들었다고 가정해보자 먼저 여기서 부터 문제가 발생한다.
1. 다크모드 상태는 전역으로 관리되어야 하는 경우가 있다.

  • 다크모드가 전역적으로 상태가 공유되어야 한다면, 모든 컴포넌트는 앞으로 props로 항상 darkMod를 공유 받아야 한다. 그렇기 때문에 만약 사용되지 않더라도 후의 컴포넌트에서는 물려줘야 하는 경우가 있을수도 있기 때문에, 항상 가지고 있어야 하며 언제든지 물려줘야할 준비가 되어있어야 한다.
  1. 다크모드는 최상위 컴포넌트에서 관리를 하는 것이 일반적이다.
  • 다크모드가 만약 최상위 컴포넌트에서 관리가 되어있다면 계속 props를 넘겨주고 또 핸들링 하는 함수를 넘겨줘야 한다. 벌써부터 끔찍하다. 다크모드 하나여서 그렇지 별도의 다른 복잡한 props를 전역으로 관리해야 한다면?

위와 같은 현상을 바로 props drilling 이라고 한다. props를 드릴처럼 계속 파고 파고파고 들어가기 때문에 위와 같은 이름이 붙은 것이다.

react는 컴포넌트 단위로 ui를 관리하여 또 재사용성을 높인 라이브러리이기 때문에, props drilling은 필연적으로 있어질수 밖에 없다. 그리고 또 props가 10개 20개만 넘어가도 정말 코드가 복잡하고 더러워 지기 때문에, 우리는 이 현상을 방지 하기 위해서 상태관리 라이브러리를 사용하게 된다.

바로 위와 같은 props drilling을 방지 하기 위해 처음으로 나온것이 redux이다. redux는 flux 패턴을 사용으로 가볍게 디자인 되었으며 store에서 가져올수 있는... 복잡하다. flux패턴은 또 뭐고 store는 뭔가?

view 즉 보여지는 컴포넌트는 action을 통해 Dispatcher 라는 것을 건들일수 있고 이 dispatcher는 store를 건들여서 변화를 시키고 또 store는 view를 건들이는 위의 패턴이 바로 flux패턴이다.

하지만 위의 패턴을 보면 알겠지만 상당히 개념이 복잡하다. 그렇기 때문에 초기의 세팅이 어렵고 복잡한 사용법을 가진 redux를 보안하기 위해서 redux toolkit 이 나왔고 또 react를 개발한 meta에서 나온 recoil과 또 zustand등등 수 많은 상태관리 라이브러리가 있다. 그중에서 내가 써본 것만 리뷰를 해보겠다.

본론

RTK

RTK는 Redux Tool Kit 의 준말로 Redux를 처음 만든 개발자가 너무 어렵게 설계를 한 자신의 과오를 인정하고 조금이라도 쉽게 사용을 하기 위해서 만든 라이브러리이다. Redux의 장점은 한번 설계를 하고 또 맞춰진 형식에 따라가기만 하면 에러가 나지 않을 정도로 초기의 보일러플레이트 설정과 함께 까다로운 사용법이 있지만 그만큼 안정성 있고 확장성또한 상당히 좋은 편이다. 하지만 단점도 명확한데 Redux의 자체는 보일러 플레이트가 많이 필요하고 초기에 뭔가 할게 많고 타입스크립트로 마이그레이션 하기도 작성하기도 상당히 까다롭다. 그렇기에 그것을 개선하고자 나온 것이 바로 RTK 이다.

RTK에서는 Redux에서 문제점이였던 보일러플레이트가 너무 많은 것을 개선하였다. 사용법은 아래와 같다.

import { configureStore } from '@reduxjs/toolkit'
// 스토어 생성
export const store = configureStore({
  reducer: {},
})

function App() {
  return (
		<Provider store={store}>
			<App />
		</Provider>,
  );
}

스토어를 생성하고 최상단 컴포넌트에 Provider를 감싸고 이제 스토어에 등록을 할 상태와 액션을 설정해주면 된다.

//darkModeSlice.js
import { createSlice } from '@reduxjs/toolkit'

const initialState = {
  value: false,
}

export const darkModeSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
   setDarkMode: (state, action) => {
     state.value = action.payload
   }
  },
})

export const { setDarkMode } = darkModeSlice.actions

export default darkModeSlice.reducer
// stroe.js
import darkModeSlice from '../features/counter/darkModeSlice'

export const store = configureStore({
  reducer: {
    darkMode: darkModeSlice
  },
})

그리고 컴포넌트에서 사용할때는 다음과 같이 사용하면 된다.

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { setDarkMode } from "./darkModeSlice";

export default function darkMode() {
  const darkMode = useSelector((state) => state.darkMode.value);
  const dispatch = useDispatch();
  
  return (
    <div>
      <div>{darkMode ? "darkMode" : "ligthMode"}</div>
      <button
        onClick={() => {
          dispatch(setDarkMode(!darkMode));
        }}
      >
        toggle darkMode
      </button>
    </div>
  );
}

위와 같은 방법으로 사용하면 된다. 확실히 기존의 redux에서는 훨씬 간편해지긴 했다. 하지만 이것조차도 초심자들이 접하기에는 할일이 많은 것은 매한가지이다. 그리고 타입스크립트 적용도 꽤 어려운 편이기도 하고.

그렇기 때문에 나는 개인적으로 이 라이브러리를 선호하지는 않는다.

정리

  • 장점: redux 보다 훨씬 간편해진 코드 구조, 안정성이 굉장히 탁월하다, 틀리면 바로 에러 집어준다, 디버깅 툴이 상당히 좋다, 타입스크립트 먹이면 오타 및 실수가 적어진다.
  • 단점: redux 보다는 간편하지만 불편하기는 마찬가지... (개인적인 의견), 러닝커브가 심한 편임, 보일러플레이트 설정이 없는 건 아님

Recoil

Recoil은 react에서 만든 meta에서 제공하는 라이브러리중 하나이다. 거기서 이야기 하기를 상당히 가볍고 사용하기 편하다 라는 것을 강조하고 제일 중요하게 생각하고 있다. redux의 store는 모든 컴포넌트가 공유를 하고 그것을 사용한다는 개념이라면, recoil은 atom이라는 개념을 차용해 언제 어디서든지 필요한 곳에서 해당하는 상태만 가져와서 그것을 불러오는 패턴을 가진다고 한다.

개발자가 직접 어떤 개념인지 설명하는 영상이다.
https://www.youtube.com/watch?v=_ISAA_Jt9kI

리액트에서 만든 곳에서 만든 라이브러리 인지는 모르겠지만 사용법도 useState 를 사용하는 것과 상당히 유사하다.

사용법을 간단히 알아보자.

먼저 atom을 불러와서 사용할것을 등록해주고 최상단 컴포넌트에 recoilRoot를 감싸주기만 하면 끝이다.

//app.jsx
function App() {
  return (
    <RecoilRoot>
      <CharacterCounter />
    </RecoilRoot>
  );
}

//atom.js
const darkModeState = atom({
  key: 'darkMode', 
  default: false, 
});

이러면 끝 그리고 이것을 useState 처럼 가져와서 적당히 사용만 해준다면 끝이다.

import React from "react";
import useRecoilState from "recoil"
import {darkModeState} from "./atom"

export default function darkMode() {
  const [darkMode, setDarkMode] = useRecoilState(darkModeState)
  return (
    <div>
      <div>{darkMode ? "darkMode" : "ligthMode"}</div>
      <button onClick={() => setDarkMode((prev) => !prev)}>
        toggle darkMode
      </button>
    </div>
  );
}

어때요 정말 쉽죠??? 위의 RTK에 비해서는 상당히 기존에 있었던 절차가 생략되고 직접 상태를 관리할 수 있다. 값만 사용하고 싶다면 useRecoilValue 를 값을 수정만 하고 싶다면 useSetRecoilState 둘다 사용하고 싶다면 useRecoilState 를 사용하면 된다. selector 는 해당하는 상태를 직접적으로 변화 시키지 않고 해당하는 상태를 복사해서 새로운 상태를 만들어주는 개념이다. 이게 끝이다. 비동기 함수로도 사용할 수 있지만 필자는 react-query를 훨씬 더 선호하기 때문에, 그냥 가능 하다는 것만 알아두었다.

정리

  • 장점: react를 사용한다면 친숙한 문법, 간단한 사용법, 가벼움
  • 단점: 업데이트가 느림 아직 정식버젼이 아님, 떨어지는 인지도

Zustand

zustand는 redux 에 조금더 근접한 형태의 상태관리 라이브러리이다. 기존에 있던 redux의 단점 이였던 복잡한 보일러 플레이트와 사용법을 개선하기 위해서 나온 라이브러리로 코드의 간결함을 추구하고 있다.

사용법은 정말 간단하다 별도의 세팅 필요없이 store를 생성하고 그것을 사용하면 된다.

//store.js
const darkModeStore = import { create } from 'zustand'

const useStore = create((set) => ({
  darkMode: false,
  setDarkMode: (darkMode) => set(() => {darkMode})
}))

export const useDarkModeState = () => darkModeStore((state) => state);

이렇게 생성하고 컴포넌트에서 그걸 불러와서 사용하면 끝!

import React from "react";
import { useDarkModeState } from "./store.js"

export default function darkMode() {
  const {darkMode, setDarkMode} = useDarkModeState()
  
  return (
    <div>
      <div>{darkMode ? "darkMode" : "ligthMode"}</div>
      <button onClick={() => setDarkMode((prev) => !prev)}>
        toggle darkMode
      </button>
    </div>
  );
}

어때요 진짜 정말 쉽죠?

정리

  • 장점: 간결함의 끝판왕, 코드읽기 쉬움, 직관적인 사용법, 공식문서 잘되어 있음
  • 단점: RTK에 비해서 떨어지는 인지도

마무리

이렇게 간단하게 사용하는 방법을 알아보았고 느낀점까지 적어보았다. 필자는 개인적으로 recoil을 애용하다가 한번 zustand를 써보고 나서 요즘은 zustand를 좋아하게 되었다. 하지만 내 마음속에는 언제나 recoil이 짱인듯 하다,,, 아무튼 각자 라이브러리의 취향이라는 게 있고 또 상황에 맞춰서 알맞은 라이브러리를 사용하는 것이 좋다!

profile
항상 즐겁고 재밌게!

0개의 댓글