지난 포스팅에서 react query에 대해서 다룬 이후 오늘은 리액트의 상태 관리 라이브러리가 무엇이고 어떻게 등장했고 어떤 종류가 있는지에 대해서 알아볼 것이다.
(내용이 많아서 종류별 특징은 다음 포스팅에서 다룰 예정이다..🥹)
지금까지는 useState
와 같은 훅을 사용하면서 상태 관리를 해왔는데 상태 관리 라이브러리는 왜 등장하게 된걸까?
초창기의 리액트는 MVC패턴의 구조를 따랐다고 한다. 하지만 양방향 데이터 이동이 가능한 MVC구조는 관리해야 할 상태와 해당 상태를 핸들링하는 컴포넌트 구조가 많아지면서 매우 복잡해지며 props drilling
문제를 겪게 되었다.
props drilling이란?
컴포넌트들은 서로 props의 형태로 상태를 공유한다.
자식 컴포넌트간에는 상태 공유가 불가능하고 부모 컴포넌트를 통해서만 공유할 수 있다. 컴포넌트의 계층이 많아질수록 props하나를 전달하는 데에 거쳐야 하는 컴포넌트가 많아지고 중간에 껴있는 컴포넌트들은 사용하지 않는 props를 가지고 있어야 하는 불편한 점이 있다.
이러한 문제를 props drilling이라고 하는데 이를 방지하기 위해서 전역으로 상태를 관리해 줄 필요가 있는 것이다 !!
위의 문제점들을 인식한 facebook이 단방향 데이터 흐름과 상태를 통합 관리하는 Store 등의 개념이 담겨있는 Flux아키텍쳐를 발표했다.
Flux는 React를 이용한 UI구성에서 데이터의 흐름을 관리하는 애플리케이션 아키텍쳐로 MVC구조의 단점을 해결할 수 있다.
View
와 View Model
사이 양방향 데이터 이동이 가능하고 View
가 많아 질수록 데이터의 흐름을 관리하기 어렵다.Model
-> View
)만 가능하기 때문에 MVC 아키텍처는 적용하지 않음View
로 분산된 state를 통합 관리한다.Action, Store, Dispatcher, View
로 구성된다.View
각각의 state는 Store
를 이용해 통합 관리되며 Store
의 데이터는 Action
을 이용해 제어한다.Store
에서 제어하는 state는 곧 연결된 View
의 state와 다름없으며 Store
의 state가 변경되면 View
도 갱신된다.위에서 다룬 Flux 아키텍쳐를 기반으로 등장한 상태 관리 라이브러리가 바로 Redux
이다!
action
이 발생하면 dispatcher
에 의해 store
에 변경된 사항이 저장되고 그 상태에 의해서 view
가 변경되는 단방향의 데이터 흐름 구조를 갖는다.
action
: 상태를 변경시키는 이벤트로 상태를 어떻게 변경시킬지를 의미한다.action
이 발생하면 거기서 반환되는 객체는dispatch
의 인자로 넘어간다.dispatch
함수는 reducer
함수를 호출한다.reducer
는 store
를 직접 업데이트한다. (state는 reducer
를 통해서만 업데이트 될 수 있다!!!)하지만 이 외에도 Reducer등 많은 문법이 필요하고 제대로 활용하기 위해서는 리덕스와 함께 사용되는 미들웨어들을 익혀야 하기 때문에 입문 난이도가 매우 높다는 단점이 있다..!
그래서 대체로 redux-toolkit을 설치해서 함께 사용을 하고 redux saga를 이용해 비동기 처리를 한다고 한다.
(각각에 대한 자세한 내용은 다음 포스팅에서!!!)
리덕스의 높은 진입장벽을 극복할 수 있는 다른 상태 관리 라이브러리들도 여럿 등장했다.
MobX
와 같은 다른 라이브러리들은 대부분 컴포넌트 외부에 Store
를 두고 컴포넌트에서 필요한 데이터를 참조하는 형태였는데 리액트에서 이와 유사한 개념으로 Provider
라는 공통 조상을 만들어 하위 컴포넌트에게 데이터를 제공하는 ContextAPI
를 발표하였고 곧이어 Hooks
가 등장한다!
상태 관리 라이브러리에 대해 알기 전의 나 역시 리액트에서 제공하는 useContext
, useState
와 같은 훅을 사용하며 상태를 관리해왔다.
하지만 이들의 문제는 상태가 변화하면 하위 컴포넌트들이 모두 리렌더링되는 문제, 나아가 위에서 본 props drilling 문제 등이 존재한다.
위에서 다룬 상태 관리 라이브러리들은 로컬 상태와 전역 상태, 즉 상태의 범위에 집중했다. 하지만 상태의 성질에 초점을 맞춘 라이브러리들이 등장하기 시작한 것이다.
서버 상태가 늘어날 수록 데이터 캐싱, 중복 요청 방지, 변경 요청과 이에 따른 동기화, 로딩 및 에러 등 비동기 라이프 사이클 관리 등의 작업을 반복해야 하는 만큼 복잡성이 늘어난다.
이를 해결하기 위해 서버 상태 관리에 특화된 라이브러리가 바로 지난 포스팅에서 다룬 React Query
인 것이다!!
리덕스와 같은 라이브러리들은 top down(하향식) 접근법을 적용한다. 필요한 상태를 모두 컴포넌트 트리 상단의 Store가 가지고 있고 하위 컴포넌트에서 필요한 상태를 가져다 쓰는 방식이다.
반대로 상향식 접근법을 채용해 상태를 업데이트하고 atom
이라는 단위를 사용해 관리하고 atom
이 업데이트 될 때마다 이 atom
을 구독한 컴포넌트가 리렌더링이 되게 하는 atomic model을 가진 방식이 등장한다.
atom
을 조합해가며 간단한 상태부터 복잡한 상태까지 다룰 수 있으며 atom
의 의존성에 따른 기본적인 렌더링 최적화가 되어 있어 추가적인 메모제이션 작업도 필요없다고 한다!
atomic model을 사용하는 리액트 라이브러리로는 Recoil
, Jotai
등이 있다.
(이 두 가지에 대해서도 다음 포스팅에서 자세히..!!)