10장 상태 관리
10.1 상태 관리
10.1.1 상태
- 상태 : 렌더링에 영향을 줄 수 있는 동적인 데이터 값
- 지역상태 : 컴포넌트 내부에서 사용되는 상태 (보통 useState, useReducer와 같은 훅 사용)
- 전역상태 : 앱 전체에서 공유하는 상태
- 서버상태 : 사용자 정보, 글 목록 등 외부 서버에 저장해야 하는 상태
10.1.2 상태를 잘 관리하기 위한 가이드
-
상태가 업데이트될 때마다 리렌더링이 발생하기 때문에 상태의 개수를 최소화는 것이 바람직
-
어떤 값을 상태로 정의할 때는 다음 2가지 사항을 고려해야 한다.
- 시간이 지나도 변하지 않으면 상태가 아니다
- 파생된 값은 상태가 아니다
-
시간이 지나도 변하지 않으면 상태가 아니다.
- 시간이 지나도 변하지 않는 값이라면 객체 참조 동일성을 유지하는 방법을 고려해볼 수 있다.
- 상수 변수를 저장하여 사용할수도 있지만 그러면 렌더링될 때마다 세로운 객체 인스턴스가 생성되기 때문에 컨텍스트나 props 등으로 전달했을 시 매번 다른 객체로 인식되어 불필요한 렌더링이 자주 발생할 수 있다.
- 리액트 공식 문서에 따르면 useRef가 동일한 객체 참조를 유지하려는 목적으로 사용하기에 가장 적합한 훅이다
-
파생된 값은 상태가 아니다
- 부모에게서 전달받을 수 있는 props이거나 기존 상태에서 계산될 수 있는 값은 상태가 아니다
- 파생된 값을 상태로 관리하게 되면 기존 출처와는 다른 새로운 출처에서 관리하게 되므로 정확성과 일관성을 보장하기 어렵다
- 두 컴포넌트에서 동일한 데이터를 상태로 갖고 있을 때는 두 컴포넌트 간의 상태를 동기화하는 방법을 사용하지 않고 가까운 공통 부모 컴포넌트로 상태를 끌어올려서 SSOT를 지킬 수 있어야 한다.
-
useState vs useReducer, 어떤 것을 사용해야 할까
- useState 대신 useReducer 사용을 권장하는 경우는 2가지가 있다
- 다수의 하위 필드를 포함하고 있는 복잡한 상태 로직을 다룰 때
- 다음 상태가 이전 상태에 의존적일 때
- useReducer는 '무엇을 변경할지'와 '어떻게 변경할지'를 분리하여 dispatch를 통해 어떤 작업을 할지를 액션으로 넘기고 reducer 함수 내에서 상태를 업데이트하는 방식을 정의한다
10.1.3 전역 상태 관리와 상태 관리 라이브러리
- 상태는 사용하는 곳과 최대한 가까워야 하며 사용 범위를 제한해야 한다
- 어떠한 상태를 전역으로 사용하는 방법은 크기 2가지이다
- 컨텍스트 API + useState 또는 useReducer
- 외부 상태 관리 라이브러리(Redux, MobX, Recoil 등)
- 컨텍스트 API
- 다른 컴포넌트들과 데이터를 쉽게 공유하기 위한 목적으로 제공되는 API
- 전역적으로 공유해야 하는 데이터를 컨텍스트로 제공하고 해당 컨텍스트를 구독한 컴포넌트에서만 데이터를 읽을 수 있게 된다
- 컨텍스트 API 관련한 또 하나의 팁은 유틸리티 함수를 정의하여 더 간단한 코드로 컨텍스트와 훅을 생성하는 것이다
- 컨텍스트 API는 대규모 어플리케이션이나 성능이 중요한 애플리케이션에서 권장되지 않는다
- 그 이유는 컨텍스트 프로바이더의 props로 주입된 값이나 참조가 변경될 때마다 해당 컨텍스트를 구독하고 있는 모든 컴포넌트가 리렌더링되기 때문이다
10.2 상태 관리 라이브러리
- MobX 특징
- 객체 지향 프로그래밍과 반응형 프로그래밍 패러다임의 영향을 받은 라이브러리
- MobX를 활용하면 상태 변경 로직을 단순하게 작성할 수 있고 복잡한 업데이트 로직을 라이브러리에 위임할수있다
- 객체 지향 스타일 코드가 편할 경우 추천
- Redux 특징
- 특정 UI 프레임워크에 종속되지 않아 독립적으로 상태 라이브러리를 사용할 수 있다
- 오랜시간 사용되어 다양한 요구사항에 대해 충분히 검증되어 있음
- 상태 변경 추적에 최적화되어 있어 특정 상황에서 발생한 애플리케이션 문제의 원인파악하는데 용이하다
- 보일러플레이트 코드가 생기고 사용 난도가 높음
- Recoil
- 상태를 저장할 수 있는 Atom과 해당 상태를 변형할 수 있는 순수함수 selector를 통해 상태를 관리하는 라이브러리다
- 보일러플레이트가 적고 난이도가 쉬워 배우기 쉽다
- 아직 실험적인 상태라서 다양한 요구사항에 대하 검증이 이뤄지지 않았다
- Zustand
- Flux 패턴을 사용하며 많은 보일러플레이트를 가지지 않는 훅 기반의 편리한 API 모듈을 제공하다
- 클로저를 활용하여 스토어 내부 상태를 관리함으로써 특정 라이브러리에 종속되지 않는 특징이 있다
- 상태과 상태를 변경하는 액션을 정의하고 반환된 훅을 어느 컴포넌트에서나 임포트하여 원하는대로 사용할 수 있다