4. 상태 관리
(1) useState
, useReducer
1) useState: 컴포넌트 내 간단한 상태 관리
2) useReducer: 컴포넌트 내 상태의 구조와 업데이트 로직이 복잡하거나 이전 상태에 의존적인 경우 상태 관리 함수를 컴포넌트와 분리
- redux(2015) vs useReducer(2018)
- redux의 리듀서 패턴을 컴포넌트 내에서 사용하기 위해 훅으로 만든 것
- redux는 전역 상태 관리, useReducer는 로컬 상태 관리
- 상태 업데이트 로직을 컴포넌트 외부로 분리하고 순수 함수로 상태의 불변성을 유지함(push🚫➜ concat✔)
- 사용 과정: dispatch(Action) => reducer(State, Action) => return newState
- reducer 함수 정의
- useReducer 호출
- 액션 dispatch
- 상태 업데이트
// 액션 타입 정의(ACTION_CREATOR)
enum ACTION_CREATOR {
INCREMENT = 'INCREMENT',
DECREMENT = 'DECREMENT',
}
// 초기 상태 설정(initialState)
interface State {
count: number;
}
interface Action {
type: ACTION_CREATOR;
payload?: number;
}
const initialState: State = {
count: 0,
};
// 리듀서 함수: 현재 상태와 액션을 받고 액션 타입에 따라 새 상태를 반환하는 순수 함수
const reducer = (state: State, action: Action): State => {
switch (action.type) {
case ACTION_CREATOR.INCREMENT:
return { ...state, count: state.count + (action.payload || 0) };
case ACTION_CREATOR.DECREMENT:
return { ...state, count: state.count - (action.payload || 0) };
default:
return state;
}
};
// useReducer, dispatch 사용(React 컴포넌트 내부)
const [state, dispatch] = useReducer(reducer, initialState); // reducer 함수와 초기 상태 등록하고 현재 상태와 dispatch 함수를 반환 받음
dispatch({ type: ACTION_CREATOR.INCREMENT, payload: 1 });
(2) context API: 전역 상태 관리 문맥
1) 장단점
- 장점: 모든 컴포넌트가 prop drilling 없이 독립적으로 데이터에 접근 가능
- 단점: 전역 상태를 구독하는 컴포넌트 간 종속성이 상태 관리의 복잡성을 증가시키고 유지보수를 어렵게 함. 상태 변화시 리렌더링으로 인한 성능 문제가 발생함
- 개선: 컴포넌트 간의 결합도를 낮추기 위해 가능한 컴포넌트 내부에서 상태를 관리하고, 필요한 경우에만 전역 상태를 사용하는 것이 좋음
- 사용 과정: Context.Provider({value}) => useContext
- context 생성
- Context.Provider 내부에 전역 상태 제공
- useContext 사용
// context 생성
type State = string | null;
interface StateType {
state: State;
setState: React.Dispatch<React.SetStateAction<State>>;
}
const defaultValue: StateType = {
state: null,
setState: () => {},
};
const MyContext = createContext<StateType>(defaultValue);
// defaultValue는 provider 컴포넌트가 value을 제공하지 않았을 때 사용되고, provider가 있다면 무시됨
// MyContext.Provider 컴포넌트로 데이터 공유
const [state, setState] = useState<State>(null);
<MyContext.Provider value={{ state, setState }}>
<App />
</MyContext.Provider>;
// useContext 사용(React 컴포넌트 내부)
const { state, setState } = useContext(MyContext);
(3) 상태 관리 도구
1) 클라이언트 측: UI 상태 관리
- 상태
- UI 컨트롤 상태: 사용자의 입력, 버튼 활성 여부, 드롭다운 메뉴의 선택 등
- UI 레이아웃 상태: 테마 설정, 사이드바 열림/닫힘, 모달 창의 보임/숨김 등
- 클라이언트 측 캐싱: 사용자 인증 정보, API 호출 결과 등
- 애플리케이션 로직 상태: 애플리케이션 내부에서 발생하는 이벤트나 사용자 작업에 따른 상태 변화 등
- 도구 종류
redux
@reduxjs/toolkit
: redux 코드 작성을 간소화- @reduxjs/toolkit +
react-redux
: react 컴포넌트 내 state 구독으로 리렌더링 유발, 렌더링 최적화 - MobX: 반응형 프로그래밍 패턴 사용
- Recoil: 원자(Atoms)와 선택자(Selectors) 사용
- Zustand: 가벼운 상태 관리 솔루션
2) 서버 측: 비동기적 상태 데이터 패칭, 캐싱, 동기화
- 상태
- 영구 데이터: 장기 저장 데이터. 데이터베이스, 파일 시스템, 클라우드 스토리지 등에 보관됨. 사용자 정보, 게시글 등
- 세션 데이터: 임시 저장 데이터. 로그인 세션 동안만 메모리에 유지됨. 로그인 여부, 장바구니 내용 등
- 캐싱 데이터: 일시 저장 데이터. 서버의 응답 속도 향상을 위해 자주 사용하는 데이터를 메모리에 보관. 특정 시간 동안만 유효하고 주기적으로 갱신됨
- 도구 종류
@tanstack/react-query
SWR
: 캐시된 데이터를 먼저 반환하고 데이터를 패칭하여 새로고침하는 방법 사용Apollo Client
: GraphQL 사용 애플리케이션 맞춤 도구Relay
: React와 GraphQL 사용 애플리케이션을 위한 프레임워크
'STORAGE > React' 카테고리의 다른 글
2-2. 상태 관리 라이브러리(redux, tanstack-query) (0) | 2024.04.11 |
---|---|
1. React와 컴포넌트 (0) | 2024.04.03 |
렌더링 타이밍 (0) | 2023.04.23 |
댓글