상태는 어떤 의미를 지닌 값으로
애플리케이션의 시나리오에 따라 지속적으로 변경될 수 있는 값
리액트는 단순히 UI 를 만들기 위한 라이브러리로 그 이상의 기능을 제공하진 않는다
순수 리액트로 전역 상태 관리를 한다면 Context API 가 있다
상태 관리보다는 상태 주입이라고 볼 수 있다
flux 패턴 등장 이전의 mvc 패턴은 모델과 뷰가 많아질수록 복잡도가 증가한다
페이스북 팀은 이러한 문제의 원인을 양방향 데이터 바인딩에 있다고 생각했다
뷰와 모델이 서로 변경할 수 있는 양방향 바인딩은 작성하긴 쉽지만 이해하기 어려운 코드가 된다
페이스북 팀이 단방향 데이터 흐름을 제안한 것이 flux 패턴의 시작이다
action -> dispatcher -> model -> view
단방향 데이터 흐름에는 불편함도 존재한다
사용자 입력에 따라 데이터를 갱신하고 화면을 어떻게 업데이트 하는지 코드로 작성해야 하므로 코드의 양이 많아진다
그러나 데이터 흐름은 액션이라는 한 방향으로 줄어들기 때문에 데이터 흐름을 추적하기 쉽고 코드를 이해하기 수월해진다
리액트 또한 방향 데이터 바인딩을 기반한 라이브러리이기 때문에 flux 패턴과 궁합이 잘 맞는다
리덕스 또한 최초에는 flux 구조를 구현하기 위해 만들어진 라이브러리 중 하나였다
특별한 것은 여기에 Elm 아키텍처를 도입했다는 것이다
Elm 은 웹페이지를 선언적으로 작성하기 위한 언어다
model, update, view 세가지가 Elm 아키텍처의 핵심이다
flux 와 마찬가지로 데이터 흐름을 세 가지로 분류하고
이를 단방향으로 강제해 웹 애플리케이션의 상태를 안정적으로 관리하고자 했다
리덕스는 하나의 상태 객체를 스토어에 저장해 두고 이 객체를 업데이트하는 작업을 디스패치해 업데이트를 수행한다
이러한 작업은 reducer 함수로 발생시킬 수 있는데 이 함수의 실행은 웹 애플리케이션 상태에 대한 복사본을 반환한 다음 애플리케이션에 새롭게 만들어진 상태를 전파하게 된다
하나의 글로벌 상태 객체를 통해 상태를 하위 컴포넌트에 전파할 수 있기 때문에
props drilling 문제를 해결할 수 있었고
스토어가 필요한 컴포넌트라면 connect 로 스토어에 바로 접근할 수 있다
리덕스는 하나의 상태를 바꾸기 위해 발생하는 보일러 플레이트가 너무 크기 때문에
불편한 부분도 있지만 현재는 많이 간소화 되었다
리액트에서 전역 상태를 하위 컴포넌트에 주입할 수 있는 새로운 Context API 를 출시했다 props 로 상태를 넘겨주지 않더라도 Context API 를 사용하면 원하는 곳에서 주입된 상태를 사용할 수 있게 되었다
기존의 context 인 getChildContext() 에서는 상위 컴포넌트 렌더링 시 하위 컴포넌트에서도 불필요하게 렌더링이 일어난다는 점과 사용하는 모든 곳에서 context 를 인수로 받아야 하기 때문에 결합도가 높아지는 등의 단점이 있었다
그럼에도 Context API 는 상태 관리보다는 주입을 도와주는 기능이며
렌더링을 막아주는 기능 또한 존재하지 않으므로 사용 시 유의해야 한다
리액트의 훅, 특히 useState() 의 등장으로 이전에 볼 수 없던 방식의 상태 관리가 등장했다
바로 Rect Qeury 와 SWR 이다
두 라이브러리는 모두 외부에서 데이터를 불러오는 fetch 를 관리하는 데 특화된 라이브러리지만 API 호출에 대한 상태를 관리하고 있기 때문에 HTTp 요청에 특화된 상태 관리 라이브러리라고 할 수 있다
useState 의 등장으로 여러 컴포넌트에서 동일한 인터페이스의 상태를 생성하고
관리할 수 있게 되었다
사용자 정의 훅을 만들어 사용하면 같은 상태를 여러 곳에서 함께 사용할 수 있다
useState 와 useReducer 를 기반으로 하는 사용자 정의 훅의 한계는
훅을 사용할 때마다 컴포넌트별로 초기화되므로 서로 다른 상태를 가질 수밖에 없다는 것
이러한 상태를 지역상태라고 하며 지역 상태는 해당 컴포넌트 내에서만 유효하다
이러한 지역 상태를 전역 상태로 만들어 동일한 값을 갖게 하기 위해서는
상태를 공유하는 가장 상위의 컴포넌트 부모에서 상태를 관리하고
props 로 상태를 공유하는 방법이 있다
useState 가 리액트 클로저가 아닌 다른 자바스크립트 실행 문맥에서 관리된다면
전역으로 관리할 수 있을 것처럼 보인다
하지만 이러한 방식으로는 리액트의 렌더링을 일으킬 수 없다
지역상태를 벗어나는 새로운 상태 만들기
상태를 업데이트하는 것뿐만 아니라 업데이트된 상태를 반영시키기 위한 렌더링이 필요하다
상태 업데이트를 위해서는 useState 나 useReducer 의 두 번째 인수가 실행되어야 한다
함수 외부에서 상태를 참조하고 렌더링까지 자연스럽게 일어나기 위해서는 다음과 같은 조건을 만족해야 한다
1. 컴포넌트 외부 어딘가에 상태를 두고 여러 컴포넌트에서 같이 쓸 수 있어야 한다
2. 외부 상태를 사용하는 컴포넌트는 모두 상태 변화를 알아챌 수 있어야 하고 상태 변화 시마다 사용하는 모든 컴포넌트에서 리렌더링이 일어나야 한다
3. 상태가 원시값이 아닌 개체인 경우 그 객체에 감지하지 않는 값이 변한다고 해도 리렌더링이 발생해서는 안된다
2번의 조건을 만족하기 위해서는 sotre 의 값이 변할 때마다 이를 알리는 callback 을 실행해야 하고 callback 을 등록하기 위한 subscribe 함수가 필요하다