상태는 컴포넌트 내부에서 관리되며 어플리케이션의 렌더에 영향을 미치는 자바스크립트 객체, 즉 어플리케이션의 화면에 영향을 끼치는 자바스크립트 객체이며 사용자와의 인터랙션을 통해 동적으로 계속해서 변화하는 데이터이다.
사이트가 복잡할 수록 이런 상태들은 점점 많아지고, 서로 의존하게 되어 관리하기 어려워진다.
그렇기 때문에 상태의 일관성, 즉 데이터의 무결성
은 정말 중요하다.
만약 서로 다른 여러개의 컴포넌트들이 어떤 동일한 상태를 다루면, 그 데이터의 정확성을 보장하기 위해 데이터의 변경을 제한해 데이터의 상태를 항상 같게 유지해야한다. 이런 데이터의 무결성을 위해 신뢰할 수 있는 단일 출처, 즉 동일한 데이터는 항상 같은 곳에서 데이터를 가지고 온다라는 방법론이 등장했고, React에서도 이 방법론을 택해서 사용하고 있다. 우리가 useState를 통해서만 state를 변경시켜야하는 이유이다.
상태는 크게 범위의 개념에서 전역상태(Global State)와 컴포넌트 간 상태(Cross Component State), 그리고 지역상태(Local State), 세가지로 나눌 수 있다.
지역상태
특정 컴포넌트 안에서만 관리되는 상태를 뜻한다. 다른 컴포넌트들과 데이터를 공유하지 않는다. 예를 들면, input, selectbox 등에서 사용자의 입력값을 받는 경우가 있다. (보통 Form 데이터들이 지역상태에 속한다.)
컴포넌트 상태
여러가지 컴포넌트에서 관리되는 상태를 나타낸다. 다수의 컴포넌트에서 쓰이고, 또 영향을 미치는 상태를 뜻한다. 프로젝트 곳곳에서 쓰이는 모달을 예로 들 수 있다. 보통 상위 컴포넌트에서 하위 컴포넌트로 prop을 넘겨 해당 컴포넌트까지 전달되도록 하는 Prop Drilling 방식을 필요로 한다.
전역 상태
프로젝트 전체에 영향을 끼치는 상태이다. 예를 들면, 유저 기능을 생각하면 된다. 이 또한 Prop Drilling 방식을 활용해서 부모에서 자식으로 데이터를 전달한다.
Prop Drilling이란, props를 오직 하위 컴포넌트로 전달하는 용도로만 쓰이는 컴포넌트를 거치며 컴포넌트에서 다른 컴포넌트로 데이터를 전달하는 과정이다.
상태관리의 필요성
서로 다른 두 컴포넌트에 같은 데이터가 필요하다고 할 때,
각 컴포넌트가 부모자식 관계로 되어있지 않은 이상, 각 컴포넌트 간의 직접적인 데이터 전달은 어렵다.
데이터를 부모 컴포넌트로 보내고, 다시 그 데이터 필요한 컴포넌트로 전달해야한다.
리액트에서 만든, React 컴포넌트 트리 안에서 전역 상태를 공유할 수 있도록 만들어진 방법이다.
Context API는 종속성을 주입하기위한 도구일 뿐이다. React에서의 실질적인 상태관리는 useState, useReducer를 통해 일어난다.
context는 변화하는 데이터들을 관리(초기값 저장, 현재 상태값을 읽거나 업데이트) 한다기 보다 단순히 이미 존재하는 상태를 다른 컴포넌트들과 쉽게 공유할 수 있게 해주는 역할을 한다.
props를 넘겨주지 않고도 데이터를 가져다가 사용할 수 있지만 (Prop Drilling을 피할 수 있다.) Context를 사용하게되면 컴포넌트를 재사용하기가 매우 힘들어지기때문에, 쉽게 사용하는 건 지양해야한다.
Context API는 독립된 상태의 리덕스와는 다르기 때문에 그 범위를 제대로 지정하지 않는다면, 불필요한 rerender를 일으키기도 한다. 각 Context를 잘 나누고 또 필요하다면 useMemo 등을 사용해 코드를 작성하는 것이 좋다. 하지만 useMemo 또한 연산이 들어가는 작업이기 때문에, 정말 필요한 곳에 잘 사용하는 것이 중요하다.
리덕스는 자바스크립트 앱을 위한 예측 가능한 상태 컨테이너이며 어플리케이션 전체에 대한 중앙 저장소 역할을 한다.
이벤트를 사용해서 어플리케이션의 상태를 우리가 예측 가능한 방식으로 업데이트 할 수 있게 도와준다.
Action을 Reducer에게 전달하기 위해서는 dispatch 메소드를 사용해야한다. dispatch는 Store의 내장 함수 중 하나인데, 액션 객체를 넘겨줘서 상태를 업데이트한다. 이벤트를 일어나게하는 이벤트 트리거의 역할을 한다.
*순수함수란, 다른 외부의 상태를 변경하지 않으면서도, 어떤 동일한 인자에 대해 항상 동일한 값을 리턴하는 함수이다.
서버와 클라이언트 간 비동기 작업을 쉽게 다룰 수 있게 도와주는 라이브러리다. 서버상태를 관리하는 라이브러리라 할 수 있다.
보통 Redux와 같은 전역상태관리 라이브러리들이 클라이언트의 상태에 대해서는 잘 동작하지만, 서버 상태에 대해서는 그렇게 동작하지 못하기 때문에 (명시적으로 fetch를 해야지 서버의 데이터를 최신으로 반영한다거나, 많은 컴포넌트에서 최신 데이터를 받아오기 위해 여러번 fetch를 한다던가.. 하는 등의 최적화가 어렵다.), 이와 같은 서버상태관리 라이브러리가 나타나게 되었다고 볼 수 있다.
DB 데이터의 상태 특징
어플리케이션 내에 속하지 않고, 그러므로 제어하지도 못한다. 보통은 원격에 위치한 곳에 저장되어있다.
데이터를 가져오거나 업데이트를 하기 위해서는 비동기 API가 필요하다.
나만 사용하는 것이 아니라, 다른 사람들과 함께 사용하기 때문에 언제 어떻게 Update 될 지 모른다.
(클라이언트는 서버 데이터의 snapshot만을 사용하기 때문에, 클라이언트에서 보이는 서버 데이터는 항상 최신이라고 보장할 수 없다.)
서버 상태는 내가 직접 관리할 수 있는 것이 아니기 때문에, 데이터의 만료에 따른 업데이트나 캐싱, 서버 데이터를 호출하는 과정 등에 신경을 써가며 관리를 해야한다.
React Query는 useQuery hook의 파라미터를 통해 다양한 기능을 제어할 수 있다.
swr은 데이터 가져오기를 쉽게 할 수 있는 리액트 훅이다.
HTTP캐시 무효화 전략을 쉽게 할 수 있도록 도와준다.
(메모리에 있는 데이터를 사용하는 방법)
캐시로부터 데이터를 반환한 후, fetch 요청(재검증)을 하고, 최종적으로 최신화된 데이터를 가져오는 전략이다.
React query와 같은 용도로 사용되지만
React query의 경우 5분동안 쿼리가 비활성화되면 가비지 컬렉터의 수집 대상이 된다. swr경우 쓰레기수집기능이 없고 원한다면 직접 조작해야한다. 또 훨씬 가볍고 기능이 단순한 편이라 할 수 있다.
데이터 가져오는 작업을 위한 여러가지 훅을 가지고 있다.
NextJS 만든 팀에서 만든거라서 NextJS와 잘 맞는다.
url는 전역상태를 확인할 때 키(id)자체가 된다.
때문에 어디서든 캐시데이터를 사용할 수 있다. 앱, 컴포넌트, 페이지 모든 곳에서!
fetcher는 데이터를 fetch하고 리턴하는 함수
매번 함수에 fetcher라고 쓰는 것을 피하기 위해 config를 사용해 전역적으로 둘 수 있다.
mutate를 사용하면 갱신하고 최종적으로 최신 데이터로 이를 대체하는 동안에 로컬 데이터를 프로그래밍 방식으로 업데이트할 수 있다. ⇒ optimistic UI 방식으로 사용자에게 최적화된 UI를 제공한다.
참고한 내용✨