나는 이미 zustand에 fall in love 해버려서 다른 라이브러리는 쓸 수 없는 몸이 되어버렸지만 그래도 각각 뭐하는 친구들인지는 알아볼 필요가 있다. 왜 zustand를 사용하셨죠? 라는 질문에 곰돌이가 귀여워서요 라고 대답하지 않을 수 있는 사람이 되어야 한다.
React 어플리케이션에서 서버 상태 관리를 위한 강력한 라이브러리
Tanner Linsley가 개발한 서버 상태 관리 라이브러리이다. 기존의 전역 상태 라이브러리들은 클라이언트 상태 관리에 초점을 맞췄지만, React Query는 서버 데이터 관리에 특화되어 있다. React-query라는 이름이 입에 붙지만, 2022년 Tanstack query로 공식 명칭이 변경되었다.
데이터 페칭, 캐싱, 동기화, 업데이트를 쉽게 할 수 있어 많은 사랑을 받는 라이브러리이다.
- 선언적 데이터 페칭: 복잡한 데이터 요청 로직을 간단한 쿼리로 추상화
- 자동 캐싱 및 동기화: 서버 데이터를 효율적으로 관리
- 중복 요청 방지: 동일한 데이터에 대한 여러 요청을 자동으로 통합하여 중복 요청을 방지.
- 복잡한 데이터 로딩 패턴 지원: 페이지네이션 및 무한 스크롤 등 복잡한 데이터 로딩 패턴을 쉽게 구현 가능
코드가 직관적이다. 복잡한 데이터 페칭 로직을 간단한 훅으로 구현할 수 있고, React 훅과 유사한 API 설계로 리액트 사용 경험이 있다면 러닝커브가 상대적으로 낮다.
필요한 곳에서 훅을 호출하기만 하면 되어 사용하기 편리하고, 불필요한 리페칭을 최소화하여 성능을 최적화 할 수 있어 가성비가 좋타.
React Query Devtools가 제공되어 데이터 흐름을 시각화하여 디버깅이 편리하다.
단점은...서버 상태 관리에 특화되어 있어 클라이언트 상태 관리에는 별도의 솔루션이 필요할 수 있다는점? 그런데 이는 오히려 서버 상태를 관리한다는 점에서 다른 상태관리 라이브러리와 차별되는 플러스 요소이다. React Query + Zustand로 서버와 클라이언트 상태를 쉽게 관리할 수 있다.
❤️참고자료
2023 우아콘 프론트엔드 상태관리 실전 편 with React Query & Zustand
[Javascript] React에 Zustand와 TanStack Query 함께 사용하기
npm install @tanstack/react-query
import { useQuery } from '@tanstack/react-query'
function Example() {
const { isLoading, error, data } = useQuery({
queryKey: ['repoData'],
queryFn: () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
(res) => res.json(),
),
})
if (isLoading) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>👀 {data.subscribers_count}</strong>{' '}
<strong>✨ {data.stargazers_count}</strong>{' '}
<strong>🍴 {data.forks_count}</strong>
</div>
)
}
useQuery
훅 하나로 데이터 페칭, 로딩 상태, 에러 처리까지 모두 관리할 수 있다.useQuery
훅은 쿼리 키와 쿼리 함수를 받는다. 쿼리 키는 쿼리를 고유하게 식별하는 값, 쿼리 함수는 실제로 데이터를 가져오는 비동기 함수isLoading
, error
, data
등의 상태를 반환하는데, 이를 통해 로딩 중, 에러 발생, 데이터 로드 성공 등을 쉽게 처리할 수 있다.Mutation, Query Invalidation, Prefetching 등의 유용한 기능들이 많다. 이에 대해서는 다음에 React Query를 공부하면서 제대로 정리해보겠다.
React 애플리케이션에서 상태 관리를 위한 강력한 라이브러리
MobX는 Michel Weststrate가 2015년 개발한 상태관리 라이브러리이다. React를 주 대상으로 하지만, 다른 프레임워크와도 호환이 된다.
Redux의 복잡성을 해결하기 위한 대안으로 등장하였다! 상태를 관찰 가능한(Observable) 객체로 만들고, 상태가 변경될 때 반응형(Reactive) UI 업데이트를 제공한다.
- 관찰 가능한 상태(Observable State): 상태를 관찰 가능한 객체로 만들고, 상태 변경을 자동으로 감지하여 반응형 UI를 제공한다.
- 객체 지향적 접근: 클래스와 객체를 사용하여 상태와 로직을 캡슐화할 수 있습니다.
- 자동 추적 및 반응(Auto-Tracking and Reaction): 상태 변경 시, 자동으로 관련된 모든 컴포넌트를 업데이트한다.
- 간결한 코드: 복잡한 상태 관리 로직을 간결하고 직관적인 코드로 구현할 수 있다.
- 데코레이터 활용: 데코레이터를 사용하여 클래스 기반의 상태 관리를 쉽게 구현할 수 있다.
- 상태의 중앙 집중 관리: 여러 컴포넌트에서 공유하는 상태를 한 곳에서 관리할 수 있다.
관찰 가능한 상태와, 반응형 업데이트를 활용하여 복잡한 상태 관리 로직을 간단하게 구현가능하다. 데코레이터
를 사용하여 클래스 기반의 상태 관리를 쉽게 할 수 있어 가독성이 높다.👀
자동화된 상태 관리로 상태 변경을 자동을 추적하고 업데이트 하여 개발자의 부담을 줄일 수 있고, 다양한 규모의 어플리케이션에 유연하게 적용할 수 있다.
MobX의 자동 추적 및 반응 기능은 강력한 장점이지만, 처음 사용하기에는 다소 복잡하다는 단점이 되기도 하다. 데코레이터
또한 장점이자 단점으로 얘기되는데, Class 형 컴포넌트 사용에는 문제가 되지 않지만 함수형 데코레이터로 구성했다면 별도의 HOC 래핑 처리가 필요하다는 듯.
객체지향적, 쉽고 간결한 코드가 최대 장점, 하지만 작은 커뮤니티
참고자료
우아한 기술블로그: React에서 MobX 경험기
깊이알아보는 mobx의 observer작동원리, useSyncExternalStore를 활용한 동시성 처리 로직
npm install mobx mobx-react-lite
스토어를 생성한다.
// store.js
import { makeAutoObservable } from "mobx"
class CounterStore {
count = 0
constructor() {
makeAutoObservable(this)
}
increment() {
this.count += 1
}
decrement() {
this.count -= 1
}
}
export default new CounterStore()
스토어를 사용하는 React 컴포넌트
// Counter.js
import React from 'react'
import { observer } from 'mobx-react-lite'
import counterStore from './store'
const Counter = observer(() => {
return (
<div>
Count: {counterStore.count}
<button onClick={() => counterStore.increment()}>+</button>
<button onClick={() => counterStore.decrement()}>-</button>
</div>
)
})
export default Counter
makeAutoObservable
함수로 상태를 자동으로 관찰하게 한다.observer
함수는 컴포넌트를 MobX의 반응형 시스템에 연결하여, counterStore 상태가 변경될 때마다 컴포넌트가 자동 리렌더링된다.상태관리 시장을 삼켜버릴 세계 최강의 곰돌이 Zustand를 알아보자🐻
Proxy API를 사용하여 상태의 객체 변화를 감지하고, 필요한 경우에만 컴포넌트를 리렌더링하는 경량 상태 관리 라이브러리이다. 프로그래머가 상태를 객체로 정의하여 직접 수정하고, 수정사항이 자동으로 리액트 컴포넌트가 반영된다.
- 단순성: 상태를 Proxy 객체로 정의하고, 직접 수정하여 사용한다.
- 자동 추적 및 반응: 상태 객체의 변화를 자동으로 추적하고 필요한 경우에만 관련 컴포넌트를 업데이트한다.
- 작은 크기: 경량 라이브러리로 번들 크기를 최소화 한다.
Proxy 객체를 사용한다는 점이 트그징이다. 복잡한 설정이나 패턴 없이 직관적으로 상태를 관리할 수 있다는 장점이 있다.
비교적 최근에 만들어진 라이브러리로, 커뮤니티가 작아 관련 자료나 서드파티 라이브러리가 제한적이다. 일부 오래된 브라우저나 Javascript 엔진에서는 Proxy API
를 지원하지 않아 호환성 문제가 발생할 수 있다는 단점이 있다.
npm install valtio
import React from 'react';
import { useSnapshot, proxy } from 'valtio';
// 상태 정의
const state = proxy({
count: 0,
});
// 컴포넌트 정의
function Counter() {
const snap = useSnapshot(state);
return (
<div>
<h1>{snap.count}</h1>
<button onClick={() => state.count++}>Increment</button>
</div>
);
}
export default Counter;
proxy
함수를 사용하여 상태 객체를 정의한다. Javascript의 Proxy API
를 활용하여 상태 변경을 감지한다.useSnapshot
훅을 사용하여 상태 객체의 현재 스냅샷을 가져온다. 이는 React 컴포넌트가 상태 변경을 구독하고, 변경 시 자동으로 리렌더링 되도록 한다.Valtio는 단순한 API와 효율적인 성능을 제공하여 간단하게 상태를 관리할 수 있으며, Proxy 개게를 통해 변경 사항을 자동으로 추적하여 성능 최적화에 유리한 라이브러리이다.
Facebook에서 개발한 React 상태 관리 라이브러리
React의 기존 상태 관리 패턴을 보완하여, 공유된 전역 상태와 비동기 상태를 쉽게 다룰 수 있도록 도와준다. React의 Concurrent Mode
와 잘 통합되어 있어 최신 react 기능을 활용할 수 있다.
- 간단한 API: 간단하고 직관적인 API를 제공하여 상태관리 로직을 쉽게 작성 가능
- 전역 상태 관리: Atom과 Selector을 사용하여 전역 상태를 쉽게 관리 가능
- 비동기 상태 관리: 비동기 데이터를 쉽게 처리
- 병렬 데이터 페칭: 여러 개의 비동기 상태를 병렬로 페칭하여 성능 최적화
편하게 비동기 처리가 가능하고, 유연한 상태관리와 Concurrency Mode
를 통해 동시성 처리를 지원한다는 장점이 있다. 러닝 커브가 낮다는 것도 장점. 아무래도 React를 개발한 Facebook에서 개발한 라이브러리이니만큼 React와의 호환성 하나만큼은 보장되는 듯 하다.
하지만 생각보다 버전 릴리즈가 늦고 생태계도 작다..메모리 누수 등의 이런저런 이슈로 이탈자가 점점 많아지는 추세인 것 같다.
import React from 'react';
import { RecoilRoot, atom, selector, useRecoilState, useRecoilValue } from 'recoil';
// Atom 정의
const textState = atom({
key: 'textState',
default: '',
});
// Selector 정의
const charCountState = selector({
key: 'charCountState',
get: ({ get }) => {
const text = get(textState);
return text.length;
},
});
// 컴포넌트 정의
function CharacterCounter() {
return (
<div>
<TextInput />
<CharacterCount />
</div>
);
}
function TextInput() {
const [text, setText] = useRecoilState(textState);
const onChange = (event) => {
setText(event.target.value);
};
return (
<div>
<input type="text" value={text} onChange={onChange} />
<br />
Echo: {text}
</div>
);
}
function CharacterCount() {
const count = useRecoilValue(charCountState);
return <>Character Count: {count}</>;
}
// 애플리케이션 루트
function App() {
return (
<RecoilRoot>
<CharacterCounter />
</RecoilRoot>
);
}
export default App;
RecoilRoot
로 감싼다.atom
은 recoil에서 상태를 나타내는 기본 단위다. key
와 default
값을 설정하여 상태를 정의한다.selector
은 파생 상태를 생성한다. get
함수로 파생 상태를 정의한다. useRecoilState
훅을 사용하여 atom
상태를 읽고 쓰며, useRecoilValue
훅을 사용하여 selector
의 값을 읽는다. React 개발사에서 개발한 라이브러리여서 React에 한해서만은 상대적으로 유용한 라이브러리지 않을까 생각했는데, 기대만큼의 성능을 뽑아내지는 못하는 것 같다. 대규모 프로젝트에서의 상태관리에 적용하기도 애매하고, 그렇다고 작은 규모의 프로젝트엔 다른 라이브러리를 적용하는 것이 나을 듯...?
예측가능한 상태 관리를 위한 자바스크립트 라이브러리
Redux
는 자바스크립트 어플리케이션을 위한 상태 관리 라이브러리로, 어플리케이션의 상태를 예측 가능하게 관리할 수 있도록 돕는다. 단일 저장소(store)을 사용하여 어플리케이션의 모든 상태를 관리하고, 상태 변경이 일어날 때마다 순수 함수인 reducer
를 통해 상태를 업데이트한다. 상태관리 로직을 일관성 있게 유지할 수 있다.
리액트 상태관리 라이브러리 중 학습 난이도가 최상인 라이브러리
- 예측 가능: 모든 상태 변경은 순수 함수인 reducer만으로 이루어져 상태의 변화가 예측 가능
- 중앙 집중화된 상태 관리: 단일 저장소를 사용하여 어플리케이션의 상태를 중앙에서 관리
- 디버깅 용이: Redux DevTools 등의 도구로 상태 변경 추적이 쉬움
- 유지 보수성: 상태 관리 로직이 일관되고 구조화되어 있어, 대규모 어플리케이션에 사용하기 좋음
- 미들웨어 지원: Redux-Saga, Redux-Thunk와 같은 미들웨어로 비동기 로직 처리 용이
기능적인 장점도 많지만, 압도적인 장점은 점유율과 그로 인한 활성화된 생태계인 것 같다. 정보도 많고, 툴도 많다.
장점도 많지만, 단점이 너무 치명적이다(내 기준). 일단 Redux 개념과 패턴을 익히기 위해 공부를 좀 많이 해야된다. 러닝 커브가 상태 관리 라이브러리 중에선 압도적으로 높을 것 같다.
보일러 플레이트 문제도 있다. 상태 관리를 위해 많은 설정과 코드 작성이 필요해, 초기 개발 속도에 지연이 있을 수도. 어플리케이션이 커짐에 따라 상태 관리 로직이 복잡해질 수 도 있지만, 이는 모든 상태 관리 라이브러리들이 공통적으로 겪는 어려움이고 Redux는 구조화된 상태 관리 방식으로 대규모 어플리케이션에서는 아직 Redux가 압도적인 것 같다. (소규모 프로젝트에선 쓰는건 독이에요🏴☠️)
아무튼 Redux는 선택이 아닌 필수
최소한의 보일러플레이트로 상태 관리를 지원하는 라이브러리
Recoil과 유사한 개념을 사용하지만, 더 간결한 사용법을 제공한다!
- 간단한 API: 최소한의 설정과 간단한 API를 통해 쉽게 상태를 관리
- 모듈화된 상태: 각 상태를
atom
으로 정의하여, 필요한 상태만 컴포넌트에 주입- 유연한 비동기 상태 관리: 비동기 상태 관리가 가능하며, 비동기 atom과 동기 atom을 조합하여 사용 가능
다른 경량 라이브러리와 같이, 간단한 API와 작은 번들 크기가 큰 장점이다. React 훅을 사용하여 상태를 쉽게 관리하고, React 최신 기능을 지원한다는 장점이 있다.
Recoil의 기능을 기반으로 하면서도 성능과 사용성이 개선되어, Recoil에 비해 더 안정적인 운영 환경을 제공하며, 리코일의 단점을 개선하고자 하는 개발자들에게 적합한 선택이다.
하지만 이런 최신 라이브러리들의 고질적인 단점으로 제한된 커뮤니티와 생태계가 있다.
Recoil과 유사한 아토믹 디자인을 지원하여 많이 비교되는 라이브러리이다. Recoil 개발사에 대한 신뢰성과 많은 자료를 원하면 Recoil을 사용하는 것이 좋지만, Recoil의 안정성에 대한 불신과 더 개선된 성능을 원한다면 Jotai 도입을 고려해 보는 것이 좋을 것 같다.
참고 자료
Jotai에 대해 알아보자
리액트에서 사용하는 여러 상태관리 라이브러들의 특징과 장단점을 알아보았다. 전부 직접 사용하고 비교한 것이 아닌 검색과 gpt를 사용하여 비교한 내용이라 정확하지 않을 수도...Redux와 React-query는 앞으로 공부할 예정이다. Jotai도 꽤나 괜찮게 보여서, 한번쯤 사용해보고 싶다. 일단 로고는 Zustand가 제일 귀엽다.