♚♚히어로즈 오브 더 스☆톰♚♚가입시$$전원 카드팩☜☜뒷면100%증정※

Composite·2023년 7월 4일
4
post-thumbnail

내가 예전 글이었나... 내가 이렇게 얘기한 적이 있다.

리액트 개발자들에게, 난 리덕스가 싫다.
뷰 개발자들에게도, 난 vuex가 싫다.

그래서 한 분이 왜인지 궁금하다는 댓글이 있는데, 그 댓글 쓴 한분과 궁금해하지 않을 너희들을 위해 내가 싸지르도록 하겠다.

2023-07-07: React의 Context 개념을 반대로 해석하고 넣은 병신새끼가 요기잉네.
개념을 반대로 적는 바람에 순도 속이꽉찬남자 99.9% 오류투성이라 그냥 포기하고 수정 안하고 끝내도록 하겠다. 읽지 마라.

내가 읽지 말라고 강조하기 위해 아예 눈갱 양식으로 바꿨다. 이래도 읽고싶어?

## 결국 브라우저 저장소를 사용한다.

SPA 앱에서 전역 상태관리를 쓴다.
하지만 언젠가는 반드시 페이지 전체가 새로고침되는 시나리오는 반드시 존재한다.
`History` API에 기대다가는, 결국 새로고침하거나, 어떤 모종의 이유로 페이지가 완전히 전환될 때,
공들여서 체계적으로 구축한 상태가 모두 날아가고, 다시 재구축하기 위해 어떤 전략을 사용할 지도 고민하게 된다.

그러다가 결국 손 대는건, 브라우저의 저장소 시스템이다. 쿠키, `LocalStorage`, `SessionStorage`, 그리고 `IndexedDB`.

...

이럴 거면 왜 전역 상태 시스템을 사용하는지 이해를 못하겠다.
뭐? 전역 상태 관리 시스템은 전역에서 사용하는 상태 데이터를 체계적으로 뭐 어쩌고저쩌고...

아 됐고, 그래서 결국 브라우저 저장소 쓰지? 그럼 너의 전역 상태관리 체계는 이미 실패했다.

이유? 간단하다.

1. 브라우저 저장소는 어디서든 접근이 가능하다. 전역 자체가 필요가 없다. 굳이 전역으로 관리하고 싶으면, 그냥 라이브러리 만들어 쓰면 된다.
2. 브라우저 저장소를 리액트나 뷰에 맞게 상태관리가 가능하다.
3. 전역상태관리의 가장 큰 단점은, 전역 상태관리를 불러온 모든 컴포넌트에 상태 변경을 시켰을 경우 일시적으로 거의 모든 컴포넌트가 재렌더링된다는 것이다. 리액트와 뷰같은 가상 DOM을 쓰는 기술에서는, 이중고다. 뭐? 가상DOM에 한꺼번에 담았다 렌더링하니 빠르다고? 지랄 마라. 단위가 정해져 있다. 컴포넌트 단위다. 따라서 현재 10개의 컴포넌트가 불러와졌을 때, 5개 컴포넌트가 재렌더링 대상이라면, 그 5개가 각각의 가상 DOM을 담을 공간을 준비해서 렌더링을 준비한 다음 렌더링한다. 1개의 가상 DOM 공감에 담는 그런 효율적인 방법이 있었다면 그건 혁명 그 자체지.

대안? 왜 없어? 브라우저 저장소에 상태관리를 입히면 된다.
리액트와 뷰를 예를 들어주겠다.

각 컴포넌트에서 저장소에 상태관리를 입힌 대표적인 케이스다. 물론 상태 변경 시 영향받는 모든 컴포넌트가 렌더링되는 건 동일하지만, 대신 전역 상태관리를 재구축할 필요가 없다. 게다가 구조가 필요하면, 타입을 정의하면 된다. 이 유틸리티는 타입 정의도 제공한다. 타입스크립트 뒀다 뭐하게?

- 리액트: [@react-hookz/web](https://github.com/react-hookz/web)
  - `useCookieValue` — 쿠키 값의 상태를 관리한다.
  - `useLocalStorageValue` — `LocalStorage` 의 키에 대한 상태를 관리한다.
  - `useSessionStorageValue` — `SessionStorage` 의 키에 대한 상태를 관리한다.
- 뷰: [vueuse](https://vueuse.org/)
  - `useCookie` — 쿠키 상태를 관리한다.
  - `useLocalStorage` — `LocalStorage` 의 상태를 관리한다.
  - `useSessionStorage` — `SessionStorage` 의 상태를 관리한다.

## SSR, SSG 등의 멀티 페이지 기반이면 도로아미타불.

Next.js 를 사용한다면, Auth.js 도 사용할 것이다. 예전에 NextAuth.js 라고 Next.js 만을 위한 인증 체계를 구축하는 라이브러리였으나, Vercel이 인수하고, 왠일로 Next.js 뿐 만 아니라 Nuxt.js, SvelteKit, SolidStart 등 주요 프론트엔드의 풀스택 라이브러리도 제공하는 범용성까지 제공한다.

근데, 얘기 전역 상태관리를 쓰는가?
아니, 필요한 컴포넌트에 비동기 데이터로 관리한다. 그래. 늬들이 말하는 Tanstack Query처럼.
뭐? react-query 아니냐고? 확 마.

어쨌든 SSR일 경우에는, SPA 와 달리 멀티 페이지 방식이다. SSG도 서버 힘만 없을 뿐 마찬가지다.
여기서 설마 전역 상태관리를 도입하려는 미친놈이 있을 거라고는 생각하고 싶지 않지만...

있더라. Next.js 를 위한 리덕스 확장인 `next-redux-wrapper` 가 있더라... 세상에...
그래서, 이걸 도입함으로써 Next.js 의 전역 상태관리를 서버의 힘까지 빌려서 가능해지리라...?

혹시 너희들 세션 알지? 서버에서 쓰는 세션 말이야. 세션이 뭔지 알지? 그럼 전역 상태관리를 세션으로 하는 건 어떻게 생각해?
어때? 생각만 해도 끔찍하지? 세상에 다수가 보는 페이지에 사용자 단위 일률적인 데이터 구조 잡고 전역 상태관리를 하다니...
전역 상태관리할 데이터가 꽤 큰건 알지? 이 상태관리 데이터를 동시에 수만명이 사용한다고 생각해봐. 안끔찍해?

SSG의 경우는 서버 힘을 못빌리기 때문에 SPA 시나리오와 다를 게 없는데 게다가 페이지 이동 완전히 이동되는 때를 더욱 고려했으니 상태를 잃을 가능성이 매우 크지.
그리고 그 상태를 유지하려고 결국에 뭘 빌리겠냐? 말 안해도 알지?

## 컴포넌트 간 상태를 관리하기 위해서?

여기까지 보면 지극히 SI적 생각이라면서 날 까고 싶어할 것이다. 그리고, 레거시를 위해서 어쩔 수 없는 선택이라고 말할 것이다.
난 레거시가 아닌 지금 시점에 대해 얘기를 한 것이고, 기존에 이미 전역 상태관리를 하고 있는 앱, 즉, 유지보수중인 앱은 건드리라는 말 안 하고, 아예 말린다. 걱정 마시라.

너네 자바스크립트 개발자들, 그나마 축복받은 줄 알아. 2023년 꼬라지가 아직도 백투더 퓨처인게, 현재 LTS가 자바 17이고 올해 새 LTS인 자바 21이 출시 예정인데도 불구하고 2014년에 출시한 자바 8이 아직도 현역인게 현실이고 그나마 8은 봐줄만 하지 그것도 모자라 2006년에 출시한 자바 1.6이 안정적이고 훌륭하다고 신규 프로젝트에 도입하려는 틀딱들이 아직도 건재한 게 자바시장이야.

자, 주요 프론트엔드 프레임워크인 React, Vue, Svelte 를 기준으로, 컴포넌트 간 상태를 관리한다면, 너희들은 불특정한 컴포넌트 주체로 인해 불안해서 전역 상태관리가 효율적이라고 생각할 것이다. 하지만, 결국 구현하고 나면, **사실상 이벤트 버스와 다를 게 뭔데?**

- 읽기도 전역에서 가능하지만, 쓰기도 전역에서 가능하다. 누구든 읽고 쓸 수 있을 수밖에 없다.
- 그나마 추적이 매우 어려운 이벤트 버스에 추적 기능이 추가되었으나, 결국의 사용처는 이벤트 버스와 다를 바 없다.

대안은 별 거 없다. 주요 프론트엔드 기술들은 컴포넌트 간 상태관리를 위한 내장 기능을 챙겨주었다.

- 리액트: `createContext` 훅을 통해 제공하는 `Provider` 및 소비하는 `Consumer` 또는 `useContext` 훅.
- 뷰: `provide` 와 `inject`.
- 스벨트: `setContext` 와 `getContext`.

그리고, 이들의 공통점은 Context 자체로는 반응성을 제공하지 않는다. 대신에 반응 가능한 개체를 넣으면 된다는 점 되겠다.

전역 상태관리 라이브러리는 반응해야 할 대상을 한정지을 수 없다. 하지만 이 각 제공하는 Context API를 쓰면 가능하다.
물론 전역 상태관리도 가능한 일이다. 하지만, 결국 구현하다 스케일이 커지다 보면, 주체할 수 없는 재렌더링을 보이는 너의 웹 앱을 보게 될 것이다.

따라서, 결론은,

### 전역 상태관리는 죄악이다.
### 범위적(Contextual) 상태 관리는 성역이다.

Context 는 매우 작은 단위부터 큰 단위까지 유연하게 관리가 가능하다. Context로 전역 상태관리도 가능하고, 최소한으로도 한정지을 수 있다.
전역 상태관리 비용보다, Context 상태 관리가 비용이 싸다. 그럴 수밖에. 기본적으로 반응성이 없는데.
브라우저 저장소를 연동한 전역 상태관리는 죄악 중 가장 최악의 악질적인 상태관리다.

프론트엔드 최적화? 웹 앱 성능 향상? Lighthouse 스코어?
다음 웹 앱에는 성역을 사용하라. 시각이 달라진다.

느리고, 메모리 누수로 고민하는 웹 앱에, 전역 상태관리를 논하지 않고는 백날 찾아봐야 말짱 도루묵이다.
다음 웹 앱에는, Context를 통한 최소한의 범위를 정한 상태 관리로, 광명을 찾기 바란다.~~

끗.

profile
지옥에서 온 개발자

3개의 댓글

comment-user-thumbnail
2023년 7월 7일

글 잘 읽었습니다~ 불필요한 전역상태관리 사용은 지양하자는 의미로 이해했는데, 질문이 몇가지 생각납니다.
텍스트로 전달하다보니 딱딱하게 느껴질 수 있는데, 공격하려는 의도가 아니고 순수 질문으로 봐주시면 감사하겠습니다!

  1. 성능 오버헤드
    LocalStorage, SessionStorage등에는 직렬화 된 데이터만 저장 가능한데 (IndexedDB는 object 가능했던것 같네요),
    브라우저 저장소로 전역상태관리를 대체하면
    read-write가 자주 발생하는 경우에 직렬화-역직렬화 오버헤드가 크지 않을까요?
  1. 과도한 리렌더
    "전역상태관리의 가장 큰 단점은, 전역 상태관리를 불러온 모든 컴포넌트에 상태 변경을 시켰을 경우 일시적으로 거의 모든 컴포넌트가 재렌더링된다는 것이다"

이게 리액트로 치면 Context API가 가지고 있는 단점이고, 이를 해결해 주는게 전역 상태관리 라이브러리의 장점 아닌가요?

  1. SSR,SSG === 멀티페이지?
    SSR나 SSG를 써도 SPA 로 동작할 수 있지 않나요? (Single Page Apps with Gatsby)
    SPA/MPA 가 대응되는 개념이고, SSG/SSR/CSR 가 대응되는 개념이지
    SSR과 MPA 는 대응되는 개념이 아니지 않나 싶습니다.
    때문에 SSR,SSG를 사용 하더라도, 클라이언트 단 Interactivity 를 위해 전역 상태관리를 충분히 사용할 수 있지 않나요?
1개의 답글
comment-user-thumbnail
2023년 7월 13일

제목때문에 오히려 읽고싶어지는글 ㅋㅋㅋㅋㅋ

답글 달기