본문 바로가기

카테고리 없음

Past, Present, and Future of React State Management

아래 글을 번역했습니다.

 

Past, Present, and Future of React State Management

Learn about the history of state management in React and what the preferred solutions are today.

leerob.io

 

React는 2013년 5월에 소개되었습니다. 이 패러다임의 변화는 UI가 상태의 함수라는 것이었습니다. 어떤 컴포넌트 상태가 주어지면 React는 컴포넌트의 모양을 결정할 수 있습니다. React는 state라는 개념을 기반으로 합니다. 하지만 상태는 오랫동안 React 애플리케이션을 구축할 때 가장 어려운 부분 중 하나였습니다.

 

React의 상태 관리를 견고한 도구 벨트라고 상상해 봅시다. 수년동안 이 도구 벨트를 사용하면서 필요에 따라 새로운 도구를 천천히 추가해 왔습니다. 각 도구는 매우 특정한 용도로 사용됩니다. 망치로 볼트를 조이는 것은 아닙니다. 장인으로서 여러분은 각 공구의 적절한 사용시기와 장소를 배웠습니다.

 

React를 사용한 상태 관리는 견고한 도구 벨트이지만, 모든 사람이 어떤 도구를 사용해야할지 알 수 있는 사전 경험이 있는 것은 아닙니다. 이 글에서는 상태 관리의 과거, 현재, 미래를 설명하여 팀, 프로젝트 또는 조직을 위해 올바른 결정을 내릴 수 있도록 도와드립니다.

 

Glossary

시작하기 전에 일반적으로 사용되는 몇 가지 용어를 이해하는 것이 중요합니다. 이는 정식 명칭이 아닙니다. 각 용어의 몇 가지 변형이 떠돌지만 기본 개념은 동일합니다.

 

- UI의 상태: 애플리케이션에서 인터랙션 가능한 부분(예: 다크모드 토글, 모달)을 제어하는데 사용되는 상태입니다.

- 서버 캐시 상태: 빠른 액세스를 위해 클라이언트 측에 캐시하는 서버의 상태(예: API 호출, 결과 저장, 여러 위치에서 사용)입니다. 

- Form 상태: Form의 다양한 상태(예: 로드 중, 제출 중, 비활성화, 유효성 검사, 재시도 중)입니다. 제어 및 제어되지 않는 Form 상태도 있습니다. 

- URL 상태: 브라우저에서 관리하는 상태(예: 제품 필터링, 쿼리 매개변수에 저장, 동일한 제품이 필터링된 것을 보기 위해 페이지 새로고침)

- State Machine: 시간에 따른 상태의 명시적 모델(예: 신호등이 녹색 -> 노란색 -> 빨간색으로 바뀌지만 녹색 -> 빨간색으로 바뀌지는 않음)

Past

React 컴포넌트 모델은 재사용 가능하고 composable한 애플리케이션을 만드는데 도움이 되었습니다. 각 컴포넌트에는 고유한 로컬 상태가 있었습니다. 웹 앱이 복잡해지면서 컴포넌트 간에 로직을 더 쉽게 공유할 수 있는 새로운 솔루션이 등장했습니다.

 

TimeLine

시간이 지남에 따라 상태 관리가 어떻게 발전했는지 이해하는데 도움이 되도록, 다음은 React에서 인기 있는 상태 관리 솔루션의 대략적인 타임라인입니다. 이 목록은 UI State에 중점을 두고 있습니다. 이 목록은 포괄적이진 않지만 컨텍스트를 제공하기에는 충분합니다. 

  • 2013 – Introduction
  • 2014 – Flux (many libraries)
  • 2015 – Redux
  • 2016 – MobX
  • 2018 – Context
  • 2019 – Hooks Introduced (+ React Query, SWR)
  • 2019 – Zustand
  • 2019 – xState
  • 2020 – Jotai, Recoil, Valtio
  • 2021 – useSelectedContext

이 타임라인에 항목이 나열되었다고 해서 해당 항목을 학습해야 한다는 의미는 아닙니다. 이에 대해서는 나중에 자세히 설명합니다. React에서 상태 관리의 역사를 살펴봅시다.

 

Redux

Redux는 원래 2014년에 Facebook에서 처음 제안한 패턴인 "Flux 아키텍처"의 구현으로 만들어졌습니다. Redux는 2015년에 출시되어 Flux에서 영감을 받은 라이브러리 중 가장 인기 있는 라이브러리로 빠르게 자리 잡았습니다. UI의 상태와 서버 캐싱 상태를 모두 캡슐화한 도구와 라이브러리의 에코 시스템입니다. Redux는 여전히 인기 있고 널리 사용되고 있습니다.

 

Server Caching State

React는 초창기에는 많은 상태 관리가 API에서 데이터를 가져와 애플리케이션 전체에서 사용할 수 있도록 캐싱하는 것으로 요약되었습니다. 서버 캐시 상태만 관리할 수 있고 쉽고 널리 사용되는 방법이 없었기 때문에 커뮤니티는 Redux와 같은 라이브러리에 크게 의존했습니다.

 

React 훅이 나오면서 로직을 공유 훅으로 캡슐화하는 것이 훨씬 더 접근하기 쉬워졌습니다. 이 문제를 구체적으로 해결하기 위해 SWR과 React Query와 같은 라이브러리가 등장했습니다. 

 

서버 캐싱 상태만을 위한 별도의 라이브러리가 왜 필요한가? 라고 생각할 수도 있습니다. 캐싱은 어렵습니다. 서버 캐싱 상태는 UI 상태와는 다른 문제를 해결합니다. 다음은 이러한 라이브러리가 처리하는 몇 가지 간단한 목록입니다. 

  • Polling on interval
  • Revalidation on focus
  • Revalidation on network recovery
  • Local mutation (Optimistic UI)
  • Smart error retrying
  • Pagination and scroll position recovery

직접 구현하고 싶으신가요? 아마 아닐 것입니다. 

 

React Context

v16.3에서는 컴포넌트 간에 로직을 공유할 수 있는 퍼스트 파티 솔루션을 제공했습니다. 또한 여러 수주느이 중첩된 컴포넌트를 통해 값을 프로퍼티로 전달하는 것(즉, props drilling)을 방지할 수 있게 되었습니다. React 컨텍스트 자체는 상태 고나리가 아닙니다. 하지만 useReducer와 같은 훅과 결합하면 상태 관리 솔루션이 될 수 있습니다. 이 조합은 많은 일반적인 사용 사례에서 UI 상태를 해결했습니다. 

 

 

Present

2021년에는 React에서 state 관리를 처리하는 다양한 방법이 있습니다. 커뮤니티가 다양한 유형의 state를 이해하게 되면서 매우 구체적인 사용 사례를 해결하는 더 세분화된 라이브러리가 만들어졌습니다. 

State Machines

switch문을 예로 들어보겠습니다. 상태 값이 어떤 경우와 일치하면 해당 코드가 실행됩니다. 한정된 경우의 집합이 있습니다. 이것이 가장 간단한 상태 머신으로, 상태에 대한 명시적 모델입니다.

 

switch (state) {
  case state === 'loading':
    // show loading spinner
    break;
  case state === 'success':
    // show success message
    break;
  default:
  // show error message
}

 

유한 상태 머신과 상태 차트는 컴퓨터 과학의 기본 개념이므로 React에만 국한된 것은 아닙니다. 서드 파티 라이브러리 없이도 useReducer를 사용하여 상태머신으로 전환할 수 있습니다. 

 

상태 머신은 데이터베이스, 전자제품, 자동차 등 모든 곳에서 잘 채택되고 있습니다. React 생태계에서 상태 관리가 발전하면서, 우리는 이 오래된 아이디어가 현대의 상태 관리 문제를 해결할 수 있다는 것을 깨달았습니다. 상태 머신은 폼 상태를 해결하는데 가장 널리 사용됩니다.

 

유한 상태 머신을 사용하면 애플리케이션이나 컴포넌트가 가질 수 있는 상태의 수가 한정되어 있습니다. 실제로 상태 머신은 에지 케이스를 생각하고 정의해야 할 때 버그를 발견하는데 도움이 됩니다.  이에 대한 자세한 내용은 xState 문서를 확인하거나 이 강좌를 시청하시는 것을 추천합니다. 온라인에서 전체 상태 머신을 시각화할 수도 있습니다. 전체 상태 머신을 온라인으로 시각화할 수도 있습니다. 

 

Zustand, Recoil, Jotai, Valtio, Oh My!

React 상태 관리를 위한 다양한 라이브러리가 존재하는 이유는 무엇일까요?

Figma(또는 다른 디자인 툴)을 생각해봅시다. "로컬" 상태 또는 컴포넌트가 렌더링되는 위치 외부의 다른 요소에 영향을 주는 컨트롤 툴바가 있습니다. 

 

상상할 수 있듯이 이 정도 규모의 애플리케이션에서 복잡한 상태 관리 솔루션이 필요합니다. 성능과 프레임 속도는 우수한 사용자 경험을 위해 매우 중요하므로 렌더링 시기와 방법을 제어할 수 있어야 합니다. 이와 같은 독특한 사용 사례로 인해 상태 관리 영역에서 많은 연구가 이루어졌습니다.

 

이러한 라이브러리의 차이점을 요약하기 위해 Daishi Kato의 이야기를 들어보겠습니다:

 

- Valtio는 프록시를 사용하여 mutation-style API를 제공합니다. 

- Jotai는 계산된 값과 비동기 작업에 최적화되어 있습니다. 

- Zustand는 모듈 상태에 특별히 초점을 맞춘 매우 가벼운 라이브러리입니다. 

- Recoil은 데이터 흐름 그래프를 사용하는 실험적인 라이브러리입니다. 

 

상태가 복잡하다고 해서 반드시 서드파티 라이브러리를 사용해야 하는 것은 아닙니다. React와 JavaScript로 시작하여 얼마나 걸리는지 확인할 수 있습니다. 최적화에 상태 관리 라이브러리가 필요한 경우 해당 메트릭(예: 프레임 속도)을 추적하고 측정하여 실제 문제가 해결되는지 확인할 수 있다. 명백한 필요성이 없다면 이러한 라이브러리 중 하나를 선택하지 마세요.

 

Immutable State

또 다른 논쟁은 변경 가능한 상태와 변경 불가능한 상태입니다. 정답은 없고 의견만 있을 뿐입니다. 바닐라 자바스크립트로 상태를 관리하고 있다면 변경 가능한 상태를 사용할 가능성이 높습니다. 변수를 초기화한 다음 나중에 새로운 값과 동일하게 설정할 수 있습니다. let과 const에 대한 논쟁은 계속되고 있습니다.

 

불변 상태는 React와 함께 많은 인기를 얻었습니다. 불변성을 선택한 상태 관리 솔루션은 상태를 집접 변경할 수 있도록 허용하면 더 많은 버그가 발생한다고 주장합니다. 변경 가능 솔루션 선택한 사람들은 복잡성을 감수할 가치가 없다고 주장합니다. 직접 조작은 항상 간접 조작보다 안정성이 떨어집니다. 편의성과 위험성 사이의 절충점은 여러분과 여러분의 팀에게 달려있습니다. 

 

Immer와 같은 솔루션을 사용하면 변경 가능한 코드를 작성할 수 있지만 불변으로 실행할 수 있습니다. 기본 아이디어는 현재 상태의 프록시인 초안 상태에 변경 사항을 적용하는 것입니다. 변경이 완료되면 Immer는 초안 상태의 변경 사항을 기반으로 다음 상태를 생성합니다. 

 

URL State

Amazon과 같은 이커머스 웹 사이트를 구축한다고 가정해 봅시다. React 책을 검색하고 별 4개 이상으로 필터링합니다. 이 상태는 쿼리 매개변수로 유지되고 브라우저에 의해 관리됩니다. 페이지를 새로고침하면 동일한 제품 목록이 표시됩니다. 이 URL을 다른 사람과 공유하면 다른 사람도 동일한 결과를 볼 수 있습니다.

 

이에 대한 또 다른 흥미로운 예는 Nomad List입니다. 브라우저 URL 상태를 데이터의 함수로 변환할 수 있습니다. 또한 사람이 읽을 수 있는 URL을 만들 수 있습니다. (Google이 선호합니다.)

 

Future

대규모 애플리케이션의 경우, 컨텍스트 기반 상태 관리 솔루션(예: useReducer)은 과도한 리렌더링 문제가 발생할 수 있습니다. 컨텍스트 값이 변경되면 컨텍스트를 사용하는 모든 컴포넌트가 다시 렌더링됩니다. 이로 인해 UI 인터랙션이 느리고 끊기는 느낌이 듭니다. 시각적으로 알아차릴 수 없다면 React 개발자 도구를 사용하여 리렌더링을 조사할 수 있습니다. 

 

React 팀은 컨텍스트의 성능 문제를 방지하기 위해 `useSelectedContext` 훅을 제안했습니다. 이 RFC는 2019년 7월에 소개되었으며 2021년 1월부터 기능 플래그를 통해 진행이 시작되었습니다. 이 훅을 사용하면 컨텍스트의 슬라이스를 선택하고 해당 부분이 변경될 때만 다시 렌더링할 수 있습니다.

 

이미 렌더링 성능 문제를 해결할 수 있는 방법(예: useMemo)이 있지만 컨텍스트에 대한 퍼스트 파티 솔루션이 선호됩니다. 비슷한 접근 방식을 취하는 커뮤니티 라이브러리인 useContextSelector도 있습니다. Jotai와 Formik 3에서는 이를 내부적으로 사용합니다. React 표준 라이브러리의 일부로 useSelectedContext를 사용하면 외부 라이브러리의 복잡성과 코드 크기를 줄일 수 있을 뿐만 아니라 기본적으로 더 성능이 뛰어난 옵션을 제공할 수 있습니다. 

 

장기적인 미래에 React는 어떤 컴포넌트를 다시 렌더링할지 자동으로 파악할 것입니다.("auto-memoization")

 

State Management Options

이 목록은 포괄적인 목록이 아닙니다. 또한 오픈소스이므로 동의하지 않거나 잘못된 부분이 있으면 PR을 열어주세요. 일반적으로 개발자와 팀에게 힘을 실어주는 것이 무엇이든 활용하세요. Redux에 만족하시나요? 계속 사용하세요!

Server Cache State

경험이나 팀 규모에 관계없이 SWR과 React Query는 모두 훌륭한 솔루션입니다. 어느 쪽이든 만족하실 것입니다. GraphQL을 사용중이라면 Apollo에 대해 이미 알고 계실 것입니다.

 

That's all, folks!

React 상태 관리는 지난 8년동안 크게 발전해 왔습니다. 이는 대규모 웹 애플리케이션을 구축할 때 가장 어렵고 미묘한 부분 중 하나입니다. 정보에 입각한 결정을 내리기 위해서는 다양한 유형의 상태와 그 장단점을 이해하는 것이 중요합니다. 이 글이 도움되었기를 바라며 읽어 주셔서 감사합니다.