지역 상태를 컴포넌트 간에 공유하려면 prop drilling과 리렌더링 문제가 생긴다.
지역 상태(useState)는 선언된 컴포넌트 내에서만 사용 가능하다.
그런데 컴포넌트 간에 같은 상태를 공유하고 싶다면 어떻게 해야 할까?
공통 부모 컴포넌트까지 올라가서 지역 상태를 선언해 준 후 prop으로 내려줘야 한다.
이럴 경우 먼저 prop drilling이 심하게 일어날 가능성이 높다.
게다가 렌더링 측면에서도 좋지 않다.
예를 들어 멀리 떨어진 컴포넌트 간에 상태를 공유할 경우를 생각해 보자.
심할 경우 최상위 부모에 상태 선언 후 prop으로 내려줘야 할 수도 있다.
이 경우 상태가 변했을 때 문제가 생긴다.
최상위가 리렌더링 되기 때문에 + 내려오는 하위 prop들이 변하기 때문에 어플 전체가 리렌더링 된다.
즉 컴포넌트 간 같은 상태를 공유하고자 할 때, 지역 상태는 2가지 문제점이 발생한다.
1. prop drilling
2. re-rendering
해결 방법은 크게 두 가지가 있다.
첫 번째는 context이고 그 다음이 구독 모델이다.
리액트에서는 context api를 제공해 주고 있다.
이 친구를 사용하면 prop drill을 하지 않고 prop 점프를 할 수 있게 된다.

위 그림을 보면 최상단 부모에서 상태가 쭉쭉 걸어 내려오는 것을 확인 할 수 있다.
그러나 context를 사용하면 걸어 내려오지 않습니다.

위 그림처럼 최상위에서 상태가 필요한 컴포넌트로 바로 점프해서 도달하게 된다.
이런 방식을 사용해서 상태를 사용하는 컴포넌트만 렌더링 시키는 것이 가능해진다.
그러나 이 방식에는 뼈아픈 단점이 있다.
먼저 상태 값이 객체인 경우 렌더링 최적화가 되지 않는다.
{a:1,b:2} 인 상태 값을 사용한다고 해보자.
컴포넌트 A에는 a 값만을 사용하고 컴포넌트 B에서는 b만을 사용한다.
이 경우 a 값을 변경 했을 경우, A만 리렌더링 하면 좋겠지만 B도 함께 리렌더링 된다.
context를 사용할 때에 꼭 알아야 하는 리렌더링 이슈다.
이 문제는 객체를 여러 context로 나누는 방법이 있다고 한다.
그러나 그럴 경우 컴포넌트를 감싸는 provider가 많아지는 등, 더티하고 유지 보수하기 힘든 코드가 된다.
다음은 문제는 아니지만 context 사용하는 적절한 상황이라는 게 존재한다.
context는 '문맥'이라는 뜻, 즉 이름처럼 어떤 문맥을 형성할 때 사용하는 것이 좋다.
예를 들어 한 남자의 인생을 다룬 소설을 읽고 있다고 해보자
책 초반부에서 '사랑'이라는 단어가 나올 때, 그 단어의 뜻은 로맨틱한 '에로틱 사랑'을 의미했다.
그러나 남자가 늙어버린 책 후반부에서 '사랑'은 인류애적인 '아가페 사랑'을 의미하게 된다.
같은'사랑'이라는 단어지만 문맥에 따라 다른 뜻으로 사용된다.
context도 비슷한 상황에서 쓰인다.
어떤 상태를 하위 트리에서 일관되게 사용하고 싶을 때 사용한다.
하위 트리마다 다르게 쓰여야 할 때, provider를 사용하면 효과적으로 사용할 수 있다.
즉, 하위 트리에 문맥을 형성하는 상태 값이 있을 때 사용하라고 있는 친구다.
그러므로 context는 어떤 전역 상태에는 적절하지 않을 수 있다.
예를 들어서 모달이 열렸는지 닫혔는지에 대한 정보를 저장하기에는 부적절하다.
왜나하면 특정 하위 트리 전체에 의미 있는 값이 아니기 때문이다.
그저 무작위적으로 모달을 사용하는 컴포넌트에서 사용되는 값이다.
이런 경우 어쩔 수 없이 최상위에 context provider를 주어야 한다.
가능은 하지만 context가 정체성에 그다지 맞는 사용법은 아니라고 할 수 있다.
마치 포크로 밥을 퍼먹는 느낌? 솔직히 잘 퍼먹을 수 있지만, 포크는 찍어먹을 때 쓰라고 만든 거긴 해 ㅎㅎ
지역 상태 해결 방법 두 번째는 바로 구독 모델이다.
이 경우 context로 사용하기에는 부적절해 보이는 전역 상태를 사용하기에 적합한 모델이다.

위 그림처럼 전역 상태가 컴포넌트 상위에 있지 않는다.
store는 전역 상태가 들어있는 창고인 store를 따로 빼둔다.
그 다음 해당 전역 상태를 사용하는 컴포넌트가 저 창고에서 빼오는 식으로 사용한다.
값을 사용하는 컴포넌트가 상태값을 구독해서 배달받는 느낌으로 이름을 이렇게 지은게 아닌가 싶다.(걍 내 생각, 적절한 네이밍 좋았다)
이런 모델을 사용하는 대표적인 예는 zustand이다.
이렇게 될 경우
prop drilling은 손쉽게 해결된다.
그리고 context에서 언급된 객체인 경우 렌더링 최적화가 되지 않는다는 문제는 어떨까?
동일한 문제가 발생은 하지만 selector라는 것을 활용해 해결할 수 있다.
{a:1,b:2}일 때 필요한 a만 select하는 기법이다.
구현하는 방식은 라이브러리마다 다르고 어떻게 구현하느냐에 따라 달라질 테니 설명은 생략, 그러나 간단하니 필요하면 찾아보자.
context보다는 조금 손쉽 효율적인 해결책이라고 한다.
구독 모델은 전역상태 관리에 모델로 널리 쓰이고 있으면 대표적인 예시가 zustand라고 할 수 있다.
zustand를 사용할 때 그러니 꼭 selector 기능을 사용해 렌더링 최적화를 하라.
구독 모델은 같은 구조의 상태를 하위 트리 문맥에 따라 다르게 사용하지 못한다.
이런 경우는 context가 좋다.
그래서 이 둘은 혼합해서 사용할 수 있다.
두 가지 장점을 모두 취하는 방식으로 만들어진 대표적인 라이브러리가 바로 jotai다.
jotai에는 context처럼 provider를 제공하니 활용할 수 있으면 활용해 보자.
나는 모달이나 split view처럼 열고 닫아야 하는 값을 전역 상태로 관리하고자 한다.
이 경우 구독 모델이 더 적절해 보이니, 구독 모델 전역 상태를 직접 구현해 보고자 한다.