도리쓰에러쓰

[React] 상태관리 라이브러리 어떤걸 써야할까? 본문

React/React

[React] 상태관리 라이브러리 어떤걸 써야할까?

강도리 2022. 8. 18. 16:22

리액트를 사용하면 빠질 수 없는 라이브러리가 바로 '상태 관리 라이브러리'이다.

뷰나 앵귤러와 비교했을 때 가장 큰 차이점은 단방향 바인딩인데,

부모 컴포넌트에서 자식 컴포넌트로만 state를 props로 전달할 수 있고, 반대로 부모 컴포넌트로 props를 직접 전달할 수는 없다.

자식 컴포넌트에서 부모 컴포넌트에 있는 state를 변경하려면 setState를 props로 넘겨줘야 한다.

 

이것이 반복되다 보면 Props Drilling이 발생하게 되고 프로젝트의 규모가 커질수록 props의 depth가 증가하게 된다.

이는 불필요한 리렌더링을 발생시킬 수 있다.

 

그럼 props로 모든 state를 관리하는 것은 추천하지 않는가?

컴포넌트의 재활용성, 의존성 분리 등의 측면에서의 props를 state로 관리하는 것은 좋다고 생각한다.

다만 프로젝트 전반적으로 사용되는 데이터를 전역으로 사용하고 그에 대한 부가적인 state를 props로 처리하면 더 효율적이라고 생각한다.

 

상태 라이브러리 종류가 다양한데 어떤 것을 사용해야 할까?

Redux, Tanstack-query, Recoil 등 많은 라이브러리가 존재하고 있다.

그렇기 때문에 각 라이브러리마다 장단점을 확인하고 프로젝트 특성에 맞게 사용하면 좋을 것 같다.

그럼 지금부터 '상태 관리 라이브러리' 종류에 대해 알아보자.


1. Redux

위 그림처럼 Redux는 데이터의 흐름이 단방형으로 흐르는 구조이다.

action, reducer, selector, store를 세팅하는 보일러플레이트 코드는 유지보수라는 장점을 가지고 있지만,

상태의 개수가 적더라도 보일러플레이트 코드가 크다는 단점이 있다.

 

Redux 라이브러리의 경우 store에 모든 상태를 저장하는 중앙집중방식이다.

store는 외부 요소이기 때문에 리액트 내부에 접근할 수 없다.

그리고 비동기 데이터 처리를 하려면 saga와 같은 별도의 라이브러리를 추가적으로 사용해야 한다.

 

Redux는 데이터 관리에 보수적인 접근방식을 가지고 있는데

이는 보일러플레이트 코드가 크다는 단점이 되었지만 확장 및 디버깅에 있어서는 엄청난 강점을 가지고 있다.

  • Redux는 오직 하나의 store만 가지며, 하나의 객체 트리를 가지기 때문에 디버깅이 용이하다.
  • store 내부 상태는 action 객체에 의해서만 변경이 가능하다. 모든 state 변화들이 하나의 store에만 집중되어 있고 단방향으로 일어나기 때문에 예측 가능한 결과가 나타난다.
  • reducer는 순수함수이기 때문에 상태를 변경하는 것이 아닌 새로운 상태를 반환한다.

2. MobX

MobX는 Redux보다 사용률이 떨어진다.

Mobx의 경우 Redux와 달리 불변성에 신경쓰지 않아도 될 정도로 규칙만 잘 지키면 최적화가 잘되는데 왜 사용률이 떨어질까?

  • MobX는 store가 여러개가 될 수 있는데, 이는 분리가 용이해 편리할 수 도 있는 반면 상태 변경 시 다수의 store가 영향을 받을 수 있다.
  • Redux와 다르게 store의 데이터를 action 발행 없이 업데이트할 수 있는데 이는 구현은 쉽고 용이하나 테스트나 유지보수의 측면에서 문제를 일으킬 수 있다.

그래서 유지보수 및 확장성을 고려해야 하는 프로젝트의 경우엔 MobX는 좋지 않은 선택일 수 있다.

하지만 Redux보다 러닝커브가 낮고 보일러플레이트 코드의 양 또한 적기 때문에 프로젝트 규모가 크지 않다면 MobX를 사용하는 것이 좋을 수 있다.


3. Context API

Context API는 리액트가 자체적으로 가지고 있다.

정적인 데이터 위주로 처리하거나 업데이트가 자주 발생하지 않을 때 사용하기 적합하다.

 

복잡한 업데이트를 처리 할 때에는 비효율적인데

Provider로 감싸진 부분의 업데이트가 되지 않은 state에도 리렌더링이 발생하기 때문이다.

이런 불필요한 리렌더링을 보완하기 위해 Recoil이란 라이브러리가 나왔다.


4. Recoil

Recoil은 최근 페이스북에서 나온 라이브러리이다.

 

Recoil은 Atom과 Selector로 이루어져 있다.

Atom은 상태의 단위로, 유니크한 키값으로 구분된다.

해당 Atom을 구독하고 있으면 해당 컴포넌트들만 선택적으로 리렌더링이 된다.

 

Atom의 상태변화는 순수함수를 통해 일어나는데 이를 Selector라고 한다.

Selector는 비동기 처리 뿐만 아니라 데이터 캐싱 기능도 제공하기 때문에 비동기 데이터를 다루기에 용이하다.

이러한 접근을 통해 Recoil은 아래와 같은 특징을 가진다.

  • 보일러플레이트가 없기 때문에 리액트 지역 상태로서 단순한 get/set 인터페이스로 상태를 공유할 수 있다.
  • 동시성 모드와 양립할 수 있는 가능성이 있다.
  • 상태를 분산적으로 둘 수 있기 때문에 코드 스플리팅이 가능하다.

하지만 아직 버전이 낮아 안정성의 측면에서는 좋지 않을 수도 있다.

그래서 큰 규모의 프로젝트에서는 도입하기 어려울 것 같지만 요즘 아래처럼 라이브러리를 같이 사용하는 경우도 있다.

 

1️⃣ Rest API를 사용할 경우

: Tanstack-Query(API로부터 데이터 불러오기, 저장, 자동화) + Recoil(미니 리덕스)

 

2️⃣ GraphQL API를 사용할 경우

: Apollo-client + Recoil

 

💡 코드 스플리팅

코드에서 당장 사용하는 부분만 로딩하고,

현재 필요하지 않은 코드 부분은 따로 분리시켜 나중에 로드함으로서 로딩 시간을 개선하는 것

 

Comments