본문 바로가기
STORAGE/React

2-1. 상태 관리 개괄

by _wavy 2024. 4. 11.

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

  1. reducer 함수 정의
  2. useReducer 호출
  3. 액션 dispatch
  4. 상태 업데이트
// 액션 타입 정의(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

  1. context 생성
  2. Context.Provider 내부에 전역 상태 제공
  3. 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

댓글