diff --git a/_posts/book/micro-state-management.md b/_posts/book/micro-state-management.md new file mode 100644 index 00000000..d68ea633 --- /dev/null +++ b/_posts/book/micro-state-management.md @@ -0,0 +1,182 @@ +--- +title: 'Micro State Management with React Hooks 리뷰' +description: '상태 관리의 종류와 기술들에 대한 이해' +tags: + ['book', 'review', 'react', 'hooks', 'context', 'zustand', 'jotai', 'valtio'] +coverImage: 'https://github.com/1ilsang/dev/assets/23524849/3a57dcf8-43b1-4e95-ae8d-2b5194c83122' +date: '2024-03-01T00:00:00.000Z' +ogImage: + url: 'https://github.com/1ilsang/dev/assets/23524849/3a57dcf8-43b1-4e95-ae8d-2b5194c83122' +--- + +![cover](https://github.com/1ilsang/dev/assets/23524849/4e361695-129c-4d6b-885e-ad8805549b4a 'cover') + +[Micro State Management with React Hooks](https://product.kyobobook.co.kr/detail/S000061587593) 리뷰를 해보려고 한다. + +## 선택하게 된 계기 + +이 책은 작년에 읽었었는데, 당시에는 이해가 많이 안 돼서 깊이 있게 생각하지 못했었다. + +실무에서 [Jotai](https://github.com/pmndrs/jotai)를 사용하기 시작하면서 사용하는 라이브러리에 대한 이해를 높이고자 다시금 이 책을 읽게 되었다. + +이 책은 세 가지 흥미로운 부분이 있다. + +1. 원서다. 영어 기술 서적은 처음 읽어서 꽤 도전적이었다. +2. Zustand, Jotai 등을 만든 상태관리에 진심인 메인테이너 [Daishi Kato](https://github.com/dai-shi)가 직접 펴낸 책이다. +3. React에서의 상태 관리 전략을 다양하게 보여주기 때문에 시야가 넓어진다. + +다 읽고 나서 알게 되었는데, [이 책은 최근에 한국어로 번역되었다](https://product.kyobobook.co.kr/detail/S000212233308)(-\_-). 이때 아니면 언제 원서 읽었겠나 싶어 만족하려고 한다. + +## 간단한 요약 + +- 상태란 무엇일까? +- 상태는 어떻게 존재할 수 있을까? +- 상태를 변화시키는 방법은 어떤 것들이 있을까? +- React hooks은 상태 관리 라이브러리에 어떤 영향을 주었을까? +- 우리는 리렌더링을 어떻게 회피할 수 있을까? + +이 책을 읽으면서 얻을 수 있었던 인사이트들이다. + +너무 어렵게 들어가지 않으면서 상태 관리의 다양한 기법들을 제시하기 때문에 주니어부터 시니어까지 충분히 배울게 많은 책이라는 생각이 든다. + +## 인상 깊었던 부분 + +책을 읽으면서 좋았던 예제나 포인트들을 가볍게 소개하고자 한다. + +### 1. React State에 대한 이해 + +React에서 상태(state)는 UI를 나타내는 모든 데이터다. React는 상태와 함께 렌더링 할 컴포넌트를 처리한다. + +책의 서두에서 기존 상태 관리의 문제점에 대해 이야기한다. + +```md +React Hooks 이전에는 모놀리식 상태 라이브러리들이 유행했다. +이는 DX 향상에 큰 도움을 주었지만 사용되지 않는 기능들도 포함된다는 문제가 있었다. + +1. Form 상태는 글로벌 상태와 별도로 다루어져야 하지만, 단일 상태 솔루션에서는 불가능하다. +2. 서버 캐시 상태는 refetching과 같은 다른 상태들과는 다른 독특한 특징을 가지고 있으나 분리가 불가능하다. +3. 브라우저 네비게이션 상태는 원본값이 브라우저 측에 기반한다는 성질이 있어 단일 상태 솔루션에 적합하지 않다. + +이런 문제들을 해결하는 것이 React Hooks의 목표 중 하나이다. +``` + +위 내용을 요약하면 Hooks 이전의 상태는 상태의 순수함이 결여되어 있었다는 점이 문제라고 꼬집는다. + +상태는 전역 상태와 지역 상태가 있다. 지역으로 존재해야 할 데이터들이 전역 스토어에 혼재되어 있고 서버/브라우저 상태가 무분별하게 스토어에 들어 있었다. + +React Hooks로 위의 내용들을 해결하고자 한다는 내용이 인상적이었다. + +### 2. useState vs useReducer + +React 컴포넌트가 상태를 가지고 있으려면 어떻게 해야 할까? + +일반 변수나 전역 변수로 선언하고 사용할 수도 있다. 하지만 해당 값이 변경되었다고 한들 컴포넌트는 리렌더링 되지 않는다. + +컴포넌트가 지역 상태의 변경을 감지하고 리렌더링 하려면 `useState` 혹은 `useReducer`를 사용해야 한다. + +> +1. React는 전역 상태를 제공하지 않는다. + +```jsx +// CASE 1. +const [count, setCount] = useState(0); +setCount(1); +setCount(1); // Not render. 동일한 값이므로 렌더링 하지 않는다. + +// CASE 2. +const [state, setState] = useState({ count: 0 }); +setState({ count: 1 }); +setState({ count: 1 }); // Re-render! 주소 참조는 항상 다른 값이 된다. + +// CASE 3. +state.count = 1; +setState(state); // Not render. state 주소값은 변하지 않았기 때문에 렌더링 하지 않는다. + +// CASE 4. +setCount(count + 1); +setCount(count + 1); // 동일하게 두 번 호출되면 +2가 아닌 +1만 될 수 있다. 이를 해결하기 위해선 함수 업데이트가 필요하다. + +// CASE 5. +setCount((prev) => prev + 1); // 함수로 작성하게 될 경우 아무리 빠르게 눌러도 횟수만큼의 업데이트가 될 것을 보장한다. 이는 내부적으로 함수를 연속적으로 호출하기 때문이다. + +// CASE 6. +setCount((prev) => prev); // 결과값이 직전과 동일하기 때문에 리렌더링이 일어나지 않는다. + +/** + * init 함수는 useState를 호출하기 전에 실행되지 않는다(lazy initialize). + * 이는 컴포넌트가 마운트 될 때 한 번만 호출함을 뜻한다. + **/ +const init = () => 0; +const [count, setCount] = useState(init); +``` + +useState의 다양한 사용 사례를 들어 리렌더링이 되는 경우를 설명한다. 또한 지연 초기화 경우를 들어 상태 관리의 최적화에 관해 설명한다. + +```jsx +const init = (count) => ({ count, text: 'hi' }); +const reducer = (state, action) => { + switch(action.type) { + case 'INCREMENT': + return { ...state, count: state.count + 1 }; + case 'SET_TEXT': + if(!action.text) { + return state; // THIS IS Bailout! 리렌더링 되지 않음. + return { ... state, text: action.text }; + default: + throw new Error(`unkown action type`); + } + } +} + +const Component = () => { + const [state, dispatch] = useReducer(reducer, 10, init); + return ( +
{state.count} + + dispatch({ type: 'SET_TEXT', text: e.target.value })} /> +``` + +`useReducer` 부분에는 `useState`에서는 불가능한, reducer만의 특별한 기능들을 언급하며 왜 useState는 useReducer로 대체 가능하지만, 역은 안되는지에 대해 설명한다. + +useState와 다르게 useReducer에서 인라인으로 함수를 선언하면 사이드 이펙트가 발생한다거나(useReducer는 렌더링 단계에서 reducer를 호출하므로) 복잡한 상태 관리를 처리하기 위한 reducer만의 기법들은 좋은 인사이트를 주었다. + +### 3. ContextAPI vs Import + +Context를 활용한 상태와 모듈(import) 상태에 대한 비교는 내가 가지고 있던 전역/지역 상태에 대한 시야를 넓혀주었다. + +> 모듈 상태는 ESM 스코프에 특정 상수 혹은 변수를 정의하는 것을 의미. +> +> `export const store = {}` 와 같다. + +우리는 전역 상태가 앱 전반에서 접근할 수 있는 상태라고 알고 있다. 그런데 이 "앱 전반"은 "React 외부에서 접근"한다는 것까지 포함해야 한다. + +ContextAPI로 작성된 전역 상태(root provider)는 React 외부에서 접근이 불가능하다. 하지만 모듈로 작성된 코드는 외부에서 접근이 가능하다. + +또한 Context는 기본적으로 [싱글턴 패턴](https://ko.wikipedia.org/wiki/%EC%8B%B1%EA%B8%80%ED%84%B4_%ED%8C%A8%ED%84%B4)을 위해 디자인되지 않았다. 여러 프로바이더에서 사용될 수 있으며 여러 서브 트리에서 다양한 상태로 존재할 수 있다. 하지만 모듈 상태는 싱글턴으로 존재한다. 따라서 단일 전역 상태를 위해서는 모듈 상태를 사용해야 한다. 이는 인메모리에 올라간 단일 변수로 취급되기 때문이다. + +### 4. Zustand vs Jotai vs Valtio + +| | [Zustand](https://github.com/pmndrs/zustand) | [Jotai](https://github.com/pmndrs/jotai) | [Valtio](https://github.com/pmndrs/valtio) | +| :-------------: | :--------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :-------------------------------------------------------------------------------------------------------------------------------------: | +| 상태의 위치 | Module | React Component | Module | +| 상태의 형태 | Immutable | Immutable | Mutable | +| 상태 변경 전략 | Selector | ContextAPI | Proxy | +| 재사용성 | 모듈 상태는 재사용이 까다롭다(싱글턴). 재사용을 위해 결국 Context를 쓰게 된다 | Provider를 통해 쉽게 재사용이 가능하다 | Zustand와 동일 | +| 코드 학습량 | 셀렉터에 대한 이해가 있어야 한다 | Context 및 Atoms에 대한 이해가 있어야 한다 | 순수 자바스크립트로 이루어져 있어 학습량이 거의 없다 | +| 리렌더링 최적화 | 개발자가 셀렉터를 잘 써야 한다 한다 | 개발자가 Atom 단위를 적절하게 활용해야 한다 | Proxy가 자동으로 해준다 | +| 비고 | 셀렉터 최적화, 객체 참조와 메모이제이션에 익숙하다면 편하게 단일 스토어를 사용할 수 있다 | Context 기반이므로 Jotai에서 가능한 것들은 Context에서도 가능하다. React LifeCycle과 공존하므로 예측 가능하다(Suspense 지원 등) | 자동 리렌더링 최적화 및 순수 JS 기반이라 편하게 사용 가능하다. 불변성을 위해 코드가 복잡해지지 않아도 된다. 하지만 디버깅 과정이 어렵다 | + +저자가 직접 만든 상태 관리 라이브러리들을 비교 하는 부분은 이 책의 하이라이트라고 생각한다. + +왜 여러 상태 라이브러리를 만들수 밖에 없었는지, 각 라이브러리의 리렌더링 회피 전략과 차이를 설명한다. 또한 공통점도 설명하는데 세 라이브러리 모두 "코드량이 적다". + +저자가 가장 중요하게 생각하는 포인트라고 생각한다. + +## 맺으며 + +기본적으로 React를 어느정도 이해하고 있는 개발자를 대상으로 작성된 책이지만 코드 자체가 어렵진 않아서 초심자도 읽어볼 만하다고 생각한다. + +책을 읽으면서 상태 관리에 대해 시야가 넓어질 수 있었다. + +다음 월간 다이브에는 "상태"를 주제로 해보려고 한다. 책을 통해 배운 것들을 잘 풀어보고 싶다. + +상태 관리의 종류와 기법들에 대해 이해하고 싶다면 추천하고 싶은 책이다. diff --git a/_posts/book/proving-ground.md b/_posts/book/proving-ground.md index d0dc7941..e8850187 100644 --- a/_posts/book/proving-ground.md +++ b/_posts/book/proving-ground.md @@ -32,7 +32,7 @@ ogImage: 그런데 그녀들의 이야기 속에서 당시 미국의 분위기를 생생하게 접할 수 있었는데 이는 또 다른 매력이었다. 책의 마지막 부에 이르러서 나는 그녀들의 행방이 궁금해 검색하지 않을 수 없었다. -## 인상깊었던 부분 +## 인상 깊었던 부분 책의 중간중간에는 당시 분위기를 엿볼 수 있는 문장들이 있다. diff --git a/_posts/book/woowa-type.md b/_posts/book/woowa-type.md index f78b2545..cf14363b 100644 --- a/_posts/book/woowa-type.md +++ b/_posts/book/woowa-type.md @@ -33,7 +33,7 @@ ogImage: 온보딩 책인 만큼 API, 리렌더링, 훅스, State 등을 다양한 예제와 패턴을 통해 소개하는데 내용이 좋으므로 사수가 없는 환경에서 개발하는 분들이라면 읽기를 추천하고 싶다. -## 인상깊었던 부분 +## 인상 깊었던 부분 책을 읽으면서 좋았던 예제나 포인트들을 가볍게 소개하고자 한다.