tech

React 상태관리 라이브러리 특징 (Redux, MobX, Recoil, Hooks)

상태 관리는 컴포넌트 간의 커뮤니케이션을 일으키고 데이터를 공유하는 간단한 방법입니다.

우리가 읽고 쓸 수 있는 앱 상태를 나타내는 구체적인 구조를 만들어 냅니다.

리액트 16.8 이후 함수형이든 클래스형이든 모든 컴포넌트는 상태를 가질 수 있게 되었습니다.

 

가장 간단한 정의로는 사용자의 액션에 따라 바뀔 수 있는 컴포넌트 부분의 자바스크립트 객체라고 말할 수 있습니다.

또는, 컴포넌트의 메모리라고도 할 수 있습니다. 사용자의 행동에 따흔 액션이 컴포넌트의 상태를 변화시킬 수 있습니다.

 

하지만, 애플리케이션의 크기가 커지면 상태관리가 매우 복잡해지며, 유지,보수에 대한 문제가 빠르게 발생할 수 있습니다.

이러한 문제를 해결할 수 있는 것이 React 상태관리 라이브러리이며, Redux, MobX, Recoil, Hooks에 대한 특징에 대해 알아보려고 합니다.

Redux

첫번째 라이브러리는 Redux입니다. Redux는 이커머스 애플리케이션의 문제점을 해결하기 위해 나왔습니다.
store이라고 불리는 자바스크립트 객체를 제공하며, 한 번의 세팅으로 애플리케이션의 모든 상태를 포함하고,

필요시 업데이트 할 수 있습니다. 조금 쉽게 설명하자면, 스토어를 구독하는 컴포넌트 밖에서 스토어를 생성하여

데이터를 꺼내서 사용할 수 있고, 스토어 상태가 변하면 컴포넌트에 함께 업데이트 되기도 합니다.

리덕스의 동작 과정은 여기 에서 볼 수 있습니다.

 

When

  1.  Redux는 한 곳에서 상태를 관리하고, 상태 변화 예측이 가능하고, 추척 가능한 상태로 유지해야 할 때
  2. 로컬에서 상태를 관리하는 것이 지저분해 보이기 시작할 때

Why

  1. 대규모 커뮤니티 지원으로 도움을 요청하고, 모범 사례를 배울 수 있으며 Redux 기반의 라이브러리를 사용할 수 있습니다.
  2. React Redux는 성능 최적화를 보장하며 필요할 떄만 연결된 컴포넌트를 재랜더링함으로 상태를 글로벌하게 유지하는 것이 용이합니다.
  3. 항상 상태 예측이 가능합니다. 동일한 상태와 액션으로 리듀서에 전달되는 경우, 순수함수인 리듀서는 동일한 결과를 얻습니다. 상태는 불변이며, 무한한 실행 취소와 재실행과 같은 작업을 구현할 수 있게 도와줍니다. 
  4. 일부 상태를 로컬 스토리지에 유지시켜 새로고침 후 복원할 수 있습니다.
  5. 서버 사이드 렌더링을 활용할 수 있습니다. 서버 요청에 대한 응답과 상태를 서버로 전송하여 앱 초기 렌더링을 처리할 수 있습니다.
  6. 유지보수성이 좋습니다. Redux는 코드 설계가 엄격하여 구조를 쉽게 이해할 수 있습니다.
  7. 쉽게 디버깅이 가능합니다. 액션과 상태를 로깅하면 코딩 오류, 네트워크 오류 및 운영 중 발생할 수 있는 버그 유형을 쉽게 이해할 수 있습니다. (about redux logger and devtools)

MobX

두번째 MobX입니다.

React와 함께 사용하는 State 관리 라이브러리 중 가장 많이 사용되고 있는 Redux와 MobX라고 합니다.

저는 Redux 사용 경험만 있어 이 둘을 비교할 수 없지만, 참고한 블로그 에서는 눈에 띄는 강력한 장점들이 있다고 하는데

매우 궁금해집니다 ! 객체 지향 느낌이 강하며 컴포넌트와 상태를 연결할 때,

보일러 플레이트 코드들을 데코레이터 제공으로 깔끔하게 해결 가능하다고 합니다.

장점은 다음과 같습니다.

  1. 객체지향적 : 도메일모델로 분리됨으로 써 집중된 비즈니스 로직은 적절히 분산되고 도메인간의 상호작용을 메세지를 주고 받는 형태로 구현이 가능합니다.
  2. 보일러 플레이트 코드가 사라지고 데코레이터가 처리하기 때문에 깔끔한 코드가 생성됩니다.
  3. 캡슐화 : MobX Configuration 설정으로 state를 오직 메소드를 통하여 변경할 수 있도록 Private하게 관리 할 수 있습니다.
  4. 불변성 유지를 위한 노력이 불필요합니다. 
  5. 낮은 러닝 커브와 가독성이 높고, 비동기 구현 시 추가 라이브러리가 필요없습니다.

낮은 러닝 커브와 가독성이 높다는 점에서 가장 끌리네요. 다음에 사용해보고 글을 쓴 후 링크 남겨놓도록 하겠습니다.

Recoil

세번째 Recoil입니다.

Recoil은 토스 레퍼런스 영상 에서 처음 알게 되었으며, 해당 영상은 비동기 처리에 대한 이야기를 다루고 있습니다.

Recoil은 현시점 가장 최신의 툴이며, 페이스북의 팀인 리액트를 개발한 엔지니어들이 제작했다고 합니다. 

 

The primary problem Recoil solves

Recoil도 마찬가지고 전역 상태를 관리하는 라이브러리입니다.

이점은 다음과 같습니다.

  1. 단순함
    Recoil의 심플함은 뒤쳐지지 않으며, Redux와 MobX와 마찬가지로 어떤 어플리케이션이든 구축할 수 있습니다. 그러나 
  2. 쉬운 러닝 커브
    Redux, MobX처럼 복잡한 상태구조를 가지고 있지 않으며 사용법이 간편하다고 합니다.
  3. 앱 전체 상태 관찰
    다른 라이브러리와 마찬가지로 앱 전체 상태 관찰을 잘 처리한다고 합니다.
  4. Redux에서 비동기 처리를 한자면 thunk, saga 등에 의존하는데, Recoil은 비동기 처리를 기반으로 작성되어 있어 동시성 모드를 지원하고 있습니다.
  5. 리액트 접근
    react를 지원하는 전용 상태관리이기 때문에 react 내부에 대한 접근이 가능하며, React의 동시성 모드, Suspense 등을 손쉽게 사용할 수 있습니다. 

When

아직 출시된지 얼마되지 않았지만, 점차적으로 대중화되고 있으며

Redux의 단점인 간단한 상태 처리에도 수많은 보일러 플레이트 코드가 필요하다는 점을 보완해주는

적은 양의 코드가 필요할 때 사용할 수 있습니다. Recoil을 언제 사용할지는 앱의 아키텍처에 따라 결정되며,

심플함을 선호하는 사람이라면 생각해 볼만 하다고 합니다.

 

아직 Recoil을 사용해 본 적은 없으나, 사용 방법이 간편하고,

비동기 작업 동시성이 가능하다는 장점이 써보고 싶게 만드는 라이브러리입니다.

쓰윽 보았을 때, Vue에서 사용하는 상태관리 방법과 비슷한 느낌이었습니다.

파이널 프로젝트 당시 Suspense를 사용하여 로딩을 표시하였는데 간편해서 좋았던 기억이 있네요.

다음 토이 프로젝트 때, 프로젝트와 성향이 맞으면 사용해봐야겠습니다.

 

* 보일러 플레이트(boilerplate)
: 변경이 거의 없이 많은 곳에서 포함되어야하는 코드 섹션, 최소한의 변경으로 여러 곳에서 재사용되는 것

Hooks

Hooks는 이랙트 라이브러리에 추가된 기능 중 가장 뛰어난 기능 중 하나입니다.

ES6 이전 함수형 컴포넌트에서 사용할 수 없었던 상태를 업데이트 후 Hooks로 인해 함수형 컴포넌트에서 '상태'를 가져다 주었습니다.

클래스형, 함수형에 관계없이 자체적으로 로컬 상태를 생성하고 관리할 수 있습니다. 

Hooks는 따로 라이브러리를 설치할 필요없이 사용 가능하여 전역 상태 관리를 훨씬 간편하게 처리할 수 있습니다. 

 

useReducer

useState의 대체 함수로 아래 형태로 사용할 수 있습니다.

다수의 하윗값을 포함하는 복잡한 정적 로직을 만드는 경우나 다음 state가 이전 state에 의존적인 경우에 보통 useState보다 useReducer를 선호합니다.

또한, 자세한 업데이트를 트리거 하는 컴포넌트의 성능을 최적화할 수 있게 하는데, 이는 콜백 대신 dispatch를 전달할 수 있기 때문입니다.

const [state, dispatch] = useReducer(reducer, initialArg, init);

 

useContext

객체를 받아 그 context의 현재 값을 반환합니다. 현재 값은 트리 안에 이 Hook을 호출하는 컴포넌트에 가장 가까이 있는 <MyContext.Provider>가 갱신되면서 value prop에 의해 결정됩니다.

컴포넌트 트리에 모든 것을 명시적으로 전달하지 않고 어디서든 상태 및 디스패치 함수를 사용할 수 있습니다. 

useContext를 호출한 컴포넌트는 context 값이 변경되면 항상 리렌더링 될 것이며.

컴포넌트를 리렌더링 하는 것에 비용이 많이 든다면, 메모이제이션을 사용하여 최적화할 수 있습니다.

const value = useContext(MyContext);

 

아무래도 Hooks는 궁금한 것도 많고, 글의 양이 꽤 될 것으로 생각되어 바로 다음 글로 풀어보아야겠습니다.


참고한 링크