1. 상태 관리
- 상태 관리 기술이란, 앱 상에서의 데이터를 메모리 등에 저장하고 하나 이상의 컴포넌트에서 데이터를 공유하는 것이다.
- 한 컴포넌트 안에서의 상태, 여러 컴포넌트 간의 상태, 전체 앱의 상태 관리를 모두 포함한다.
- 상태가 많지 않거나, 유저와의 인터렉션이 많지 않다면 매 작업 시 서버와 동기화하더라도 충분하다
- BUT 사용하는 데이터가 점점 많아지고 유저와의 인터렉션 시 임시로 저장하는 데이터가 많아지는 경우, 상태 관리를 고려해야 한다.
장단점
- 장점 :
- 높은 품질의 코드를 작성하는 데 유리
- 성능 최적화, 네트워크 최적화 등에 유리
- 데이터 관리의 고도화
- 단점 :
- Boilerplate 문제
- what? 최소한의 변경으로 여러 곳에서 재사용되며, 반복적으로 비슷한 형태를 띄는 코드를 의미
- 파악해야 할 로직과 레이어가 많아진다.
- 잘못 사용할 경우, 앱의 복잡도만을 높이거나 성능을 악화시킨다.
상태 관리가 해결해야 할 문제들
데이터 캐싱과 재활용
- SPA에서 페이지 로딩 시마다 모든 데이터를 로딩한다면, 사용자 경험 측면에서 MPA를 크게 넘어서기 힘들다.
- 오히려 네트워크 요청 수가 많아져 더 느릴 수도 있다.
- 변경이 잦은 데이터가 아니라면, 데이터를 캐싱하고 재활용함
- 변경이 잦다면, 데이터의 변경 시점을 파악해 최적화
- ex) 일정 시간마다 서버에 저장, 타이핑 5초 후 서버에 저장
Prop Drilling
- 컴포넌트가 복잡해지는 경우, 상위 부모와 자식 컴포넌트 간의 깊이가 커짐
- 최하단의 자식 컴포넌트가 데이터를 쓰기 위해 최상위 컴포넌트부터 데이터를 보내야 하는 상황이 발생
- Context API 등을 활용, 필요한 컴포넌트에서 데이터를 가져올 수 있음
- 컴포넌트 간의 결합성을 낮춤
2. Flux Pattern
: 2014년 Facebook에서 제안한 웹 애플리케이션 아키텍처 패턴
- Unidirectional data flow(일방향 데이터 흐름)를 활용, 데이터의 업데이트와 UI 반영을 단순화
- React의 UI 패턴인 합성 컴포넌트와 어울리도록 설계
- redux, react-redux 라이브러리의 Prior art.
Flux Pattern vs MVC Pattern
- MVC : Model View Controller ⇒ Bidirectional data flow (양방향 데이터 흐름)
- MVC 패턴에서는, View에서 특정 데이터를 업데이트하면 연쇄적인 업데이트가 일어남 - Bidirectional data flow이기 때문에
- 특정 유저의 인터렉션이 여러 UI 컴포넌트가 사용하는 데이터에 영향을 줄 때, MVC만으로는 앱의 복잡도를 낮추거나 업데이트의 흐름을 따라가기 힘들다
- Flux는 하나의 Action(유저 인터렉션)이 하나의 Update만을 만들도록 한다.
- data와 업데이트가 한 방향으로 흐르므로 UI의 업데이트를 예측하기 쉬움
Flux 구조
- Action → Dispatcher → Store → View 순으로 데이터가 흐른다
- store는 미리 dispatcher에 callback을 등록해 자신이 처리할 action을 정의
- action creator는 action을 생성하여 dispatcher로 보냄
- dispatcher는 action을 store로 넘김
- store는 action에 따라 데이터를 업데이트 후, 관련 view로 변경 이벤트 발생
- View는 그에 따라 데이터를 다시 받아와 새로운 UI를 만듦
- 유저 인터렉션이 발생하면 View는 action을 발생
3. useState, useRef, useContext, useReducer
상태 관리에 사용되는 훅
- 외부 라이브러리 없이 React가 제공하는 훅만으로 상태 관리를 구현하기 위해 사용
- 함수형 컴포넌트에 상태를 두고, 여러 컴포넌트 간 데이터와 데이터 변경 함수를 공유하는 방식으로 상태를 관리하게 됨.
UseState
- 단순한 하나의 상태를 관리하기에 적합
const [state, setState] = useState(초기값 or 초기함수)
- state가 바뀌면, state를 사용하는 컴포넌트를 리렌더링
- useEffect와 함께, state에 반응하는 훅을 구축
useRef
- 상태가 바뀌어도 리렌더링하지 않는 상태를 정의함
- 즉, 상태가 UI의 변경과 관계없을 때 사용 (UI의 변경이 필요 없을 때)
- uncontrolled component의 상태를 저장하는 등 리렌더링을 최소화하는 상태 관리에서 사용됨 ( 필요할 때만 데이터를 불러오는 것 )
useContext
- 컴포넌트와 컴포넌트 간 상태를 공유할 때 사용
- 부분적인 컴포넌트들의 상태 관리, 전체 앱의 상태 관리를 모두 구현
- Context Provider 안에서 렌더링되는 컴포넌트는 useContext를 이용해 깊이 nested(중첩)된 컴포넌트라도 바로 context value를 가져옴
- Context value가 바뀌면, 내부 컴포넌트는 모두 리렌더링됨
useReducer
- useState보다 복잡한 상태를 다룰 때 사용
- 별도의 라이브러리 없이 flux pattern에 기반한 상태 관리를 구현
const [state, dispatch] = useReducer(reducer, initState)
- dispatch(action) => dispatch에 action을 넘기면 reducer로 흘러간다.
- reducer에서 업데이트된 state를 리턴하고 그 후 state가 업데이트 된다.
- 그 후 이 state를 쓰는 다양한 컴포넌트들이 업데이트 된다.
- nested state 등 복잡한 여러 개의 상태를 한꺼번에 관리하거나, 어떤 상태에 여러 가지 처리를 적용할 때 유용
- 상태가 복잡하다면, useState에 관한 callback을 내려주는 것보다 dispatch를 prop으로 내려 리렌더링을 최적화하는 것을 권장