5.1 상태 관리는 왜 필요한가?
- 상태는 어떠한 의미를 지닌 값으로 애플리케이션의 시나리오에 따라 지속적으로 변경될 수 있는 값을 의미한다.
5.1.1 리액트 상태 관리의 역사
Flux 패턴의 등장
양방향 데이터 바인딩이 아닌 단방향으로 데이터 흐름을 변경함
Action -> Dispatcher -> Model -> View
- 액션(action) : 어떤 작업을 처리할 액션과 그 액션 발생 시 함께 포함시킬 데이터를 의미한다. 액션 타입과 데이터를 각 정의해 dispatcher로 전달한다.
- 디스패처(dispatcher) : 콜백 함수 형태로 액션이 정의한 타입과 데이터를 모두 store로 보내는 역할을 한다.
- 스토어(store) : 실제 상태의 값과 상태를 변경할 수 있는 메서드를 가지고 있다.
- 뷰(view) : 리액트 컴포넌트에 해당하는 부분으로, 스토어에서 만들어진 데이터를 가져와 화면에 렌더링하는 역할을 한다.
리덕스의 등장
Flux 구조 구현 + Elm 아키텍처 도입
*Elm은 웹페이지를 선언적으로 작성하기 위한 언어이다.
더보기
- 모델(model) : 애플리케이션의 상태를 의미한다.
- 뷰(view) : 모델을 표현하는 HTML을 말한다.
- 업데이트(update) : 모델을 수정하는 방식을 말한다.
- 리덕스는 하나의 상태 객체를 스토어에 저장하고 이 객체를 업데이트 하는 작업을 디스패치해 업데이트를 수행한다.
- 위 작업은 reducer 함수로 발생시킬 수 있는데, 이 함수의 실행은 웹 애플리케이션 상태에 대한 완전히 새로운 복사본을 반환한 뒤, 애플리케이션에 이 새롭게 만드렁진 상태를 전파한다.
Context API와 useContext
- props로 상태를 넘겨주지 않아도 원하는 곳에 Context Provider가 주입하는 상태를 사용할 수 있다.
5.2 리액트 훅으로 시작하는 상태 관리
5.2.1 가장 기본적인 방법: useState와 useReducer
- useState를 사용하여 커스텀 훅을 만들어 어디서든 재사용할 수 있다는 큰 장점이 있다.
- 훅 내부에서 관리해야 하는 상태가 복잡하거나 상태를 변경할 수 있는 시나리오가 다양해진다면 훅으로 코드를 분리, 격리해 제공할 수 있다.
- useState와 useReducer을 기반으로 한 훅은 사용할 때마다 컴포넌트별로 초기화되므로 컴포넌트에 따라 서로 다른 상태를 가진다. 이 지역 상태(local state)는 해당 컴포넌트 내에서만 유효하다는 한계가 있다.
5.2.2 지역 상태의 한계를 벗어나기 : useState의 상태를 바깥으로 분리하기
- useState와 useReducer는 지역 상태이므로, 해당 컴포넌트 내에서만 유효하다는 한계가 있다 .
- 이 한계는 useState가 리액트의 클로저 내부에서 관리되기 때문에 발생한다 .
- 저자는 이 문제를 해결하기 위해 useState의 상태를 외부로 분리하는 방법을 제안하며, 상태가 다른 자바스크립트 실행 문맥에서 초기화되고 관리될 수 있다면 더 넓은 스코프 내에서 객체의 값을 공유할 수 있다고 설명한다.
- 이 접근법을 구현하기 위해서는 상태가 컴포넌트 외부에 위치해야 하며, 정상적으로 리렌더링이 되어야 한다는 조건이 있다 .
- 상태를 외부에서 자연스럽게 참조하고 렌더링하기 위해서는 세 가지 조건을 만족해야 한다.
더보기
첫 번째 조건은 여러 컴포넌트가 함께 사용할 수 있도록, 컴포넌트 외부에 상태가 존재해야 한다.
두 번째 조건은 상태가 변할 때, 해당 상태를 참조하는 컴포넌트가 최신 값을 반영하기 위해 리렌더링되어야 한다.
마지막 조건은 객체 상태의 속성이 변해도 그 속성을 참조하는 컴포넌트가 없다면, 해당 컴포넌트는 렌더링이 되지 않아야 한다.
- 예를 들어, A 컴포넌트와 B 컴포넌트가 각각 스몰 A와 스몰 B라는 상태를 공유하고 있을 때, 스몰 A의 값이 변경되어도 B 컴포넌트는 리렌더링되지 않아야 한다.
5.2.3 useState와 Context를 동시에 사용해보기
- Context를 활용해 해당 스토어를 하위 컴포넌트에 주입한다면 컴포넌트에서는 자신이 주입된 스토어에 대해서만 접근할 수 있게 된다.
- 이 방식은 반드시 하나의 스토어만 가지게 되며 각 스토어는 마치 전역 변수처럼 작동하여 동일한 형태의 여러 개의 스토어를 가질 수 없게 된다.
- Context로 컴포넌트 트리 내 상태 격리가 필요한 부분에 Provider 생성한다. 각기 다른 초기값을 설정하여 개별 관리한다.
5.2.4 상태 관리 라이브러리 Recoil, Jotai, Zustand 살펴보기
- Recoil, Jotai은 Context, Provider 훅을 기반으로 가능한 작은 상태를 관리한다.
- Zustand는 리덕스와 비슷하게 하나의 큰 스토어를 기반으로 상태를 관리한다(클로저기반).
Recoil
- 컴포넌트는 Recoil에서 제공하는 훅을 통해 atom의 상태 변화를 구독하고, 값이 변경되면 forceUpdate와 같은 기법을 통해 리렌더링을 실행해 최신 atom 값을 return 한다.
RecoilRoot
- 애플리케이션 최상단에 RecoilRoot를 생성한다.
- RecoilRoot로 생성된 Context 스토어에 상태 값을 저장한다.
- 스토어의 상태값에 접근할 수 있는 함수들이 있으며, 이 함수를 활용해 상태값에 접근, 변경이 가능하다.
- 값의 변경이 발생하면 참조하고 있는 하위 컴포넌트에 모두 알린다.
atom
- 상태를 나타내는 Recoil의 최소 상태 단위이다.
- key 값을 필수로 가진다.
- default는 atom의 초깃값이다.
useRecoilValue
- atom의 값을 읽어오는 훅이다.
- 내부 useEffect를 통해 recoilValue 변경 시 forceUpdate를 통해 렌더링을 강제 수행한다.
useRecoilState
- 값을 가져오거나 변경할 수 있는 훅이다.
- 가져오는 값은 useRecoilValue로 사용한다.
- 업데이트는 useSetRecoilState로 수행한다. 내부에 있는 setRecoilValue는 queueOrPerformStateUpdate 함수를 호출해 상태를 업데이트하거나 업데이트가 필요한 내용을 등록한다.
Jotai
- 상향식 접근법이다.
- 작은 단위의 상태를 위로 전파할 수 있는 구조다.
- Context의 문제점인 불필요한 리렌더링 문제를 해결하기 위해 설계됐다.
- Recoil과 달리 별도의 키 관리가 필요없고, 객체의 참조를 통해 값을 관리한다.
- selector 없이 atom만으로 파생된 값 생성이 가능하다.
atom
- Recoil과 같은 최소 상태 단위이다.
- atom 하나로 파생된 상태까지 생성 가능하다.
- key 값이 필요없다.
- useAtomValue에 상태를 저장한다.
useAtomValue
- version은 스토어의 버전을 말한다.
- valueFromReducer는 atom에서 get 수행 시 반환하는 값이다.
- atomFromReducer는 atom 그자체이다.
- atom 값은 훅 내부의 store에서 WeakMap 방식으로 별도의 키 없이 값을 저장한다.
- rerenderIfChanged는 넘겨받은 atom이 Reducer를 통해 스토어 atom과 달라지는 경우, subscribe를 수행하는 값이 변경된 경우 리렌더링을 유발한다.
useAtom
- useState와 동일한 형태로 첫번째 값은 useAtomValue 훅의 결과를 반환하고, 두번째 값은 useSetAtom 훅을 반환하며 atom 수정이 가능하다.
- setAtom에서 사용하는 write 함수에서는 스토어에서 해당 atom을 찾아 직접 값을 업데이트 한다.
Zustand
- 하나의 스토어를 중앙 집중형으로 활용해 스토어 내부에서 상태를 관리한다.
- 내부의 partial, replace로 state의 일부분 또는 전체를 변경할 수 있다.
- useStore에서는 useSyncExternelStoreWithSelector를 사용한다. useSyncExternalStore와 다른 점은 원하는 값을 가져올 수 있는 selector와 동등 비교를 할 수 있는 equalityFn 함수를 받는다는 것이다.
- create 내에 반환값, getter, setter 함수를 작성한다.
'React-study > dil' 카테고리의 다른 글
[모던리액트 Deep Dive] 7장 크롬 개발자 도구를 활용한 애플리케이션 분석 (2) | 2024.11.20 |
---|---|
[모던 리액트 Deep Dive] 6장 리액트 개발 도구로 디버깅하기 (0) | 2024.11.18 |
[모던 리액트 Deep Dive] 3장 리액트 훅 깊게 살펴보기 (0) | 2024.11.10 |
[모던 리액트 Deep Dive] 2장 리액트 핵심 요소 깊게 살펴보기 (12) | 2024.11.06 |
[모던리액트 Deep Dive] 1장 리액트 개발을 위해 꼭 알아야 할 자바스크립트 (7) | 2024.11.05 |