React의 상태관리에 대해(Redux-Toolkit)

광부·2024년 9월 8일
0

현재 인턴으로 근무중인 회사에서 진행중인 프로젝트에서 사용중인 상태관리 툴에 대해 정리하고자 한다.
현재 진행중인 프로젝트는 클라이언트 상태 관리를 Redux-Toolkit으로, 서버 상태 관리를 React Query로 수행하고 있다.

이전까지는 프론트 코드의 구조만을 보다가 급하게 풀스택으로 작업이 필요해서 머리를 박으며 진행하다가 정리해본다.

Store

Redux에는 configureStore라는 전역 상태를 보관하는 객체가 존재한다. reducer필드에는 여러 reducer객체를 key:value형태로 전달 할 수도 있고, combinedReducer 를 호출하여 여러 reducer를 결합하여 전달 할 수도 있다.

import {configureStore} from '@reduxjs/toolkit'
import exampleReducer from './userSlice.ts'

export const store = configureStore({
	reducer: {
    	example: exampleReducer,
    },
})

Slice

Slice란 상태와 그 상태를 변경하는 reducer 함수들을 하나의 모듈로 결합한 객체이다. Slice에는 name, initialState, reducers 세 요소가 필요하다.
아래 처럼 생성된 슬라이스를 Store의 reducer필드에 등록한다.
이때 createSlice의 reducers필드에 정의된 함수에 대응되는 action creators를 만들어주고, 이를 export하게된다.
또한, Dispatch를 사용할때는 action creators로 만들어진 action을 호출하게된다. (createSlice에서 setName, setAge 같은 함수를 action으로 자동 생성한다.)

import { createSlice } from '@reduxjs/toolkit';

// 초기 상태 정의
const initialState = {
  name: '',
  age: 0,
  loggedIn: false,
};

// slice 생성
const userSlice = createSlice({
  name: 'user',    // slice의 이름
  initialState,    // 초기 상태
  reducers: {
    // 상태를 업데이트하는 reducer 함수들 정의
    setName: (state, action) => {
      state.name = action.payload;
    },
    setAge: (state, action) => {
      state.age = action.payload;
    },
    logIn: (state) => {
      state.loggedIn = true;
    },
    logOut: (state) => {
      state.loggedIn = false;
    },
  },
});

// 액션 생성자들을 export
export const { setName, setAge, logIn, logOut } = userSlice.actions;

// 리듀서 export
export default userSlice.reducer;

UseSelector

useSelector는 Redux store에 정의된 상태를 읽는 데 사용된다. useSelector 내부적으로 Redux store에 연결되어 있어 스토어에 정의된 현재 상태를 가져와 useSelector로 전달한다.

redux에 대해서 찾아보니 pubsub방식으로 상태변화를 감지한다. useSelector에 정의된 state를 Subscribe한다. 비동기 방식으로 구현하기 위해서는 당연한 구조였는데 차마 이렇게까지 응용이 될 것이라고는 생각하지 못 했다.(분산시스템 갓갓;;)

import { useSelector } from 'react-redux';

const MyComponent = () => {
  // 전체 state에서 user 상태에 접근
  const user = useSelector((state) => state.user);
  
  // 전체 state에서 product의 items 배열에 접근
  const products = useSelector((state) => state.product.items);

  return (
    <div>
      <p>User Name: {user.name}</p>
      <p>Product Count: {products.length}</p>
    </div>
  );
};

UseDispatch

useDispatch는 Redux Store에 정의된 상태를 변경하기 위해 사용된다.
기존 useState에서 생성된 setName과 같은 형식의 함수는 상태를 직접 변경하는데, Redux에서는 전역 상태관리를 액션을 통해서만 수행한다.
useDispatch는 전역 상태에 대해 액션을 발행하기 위한 유일한 방법이다.

import { useSelector, useDispatch } from 'react-redux';
import { setName, setAge, logIn, logOut } from './userSlice';

function UserProfile() {
  const dispatch = useDispatch();
  const user = useSelector((state) => state.user);

  const handleLogin = () => {
    dispatch(logIn());
    dispatch(setName('John Doe'));
    dispatch(setAge(30));
  };

  const handleLogout = () => {
    dispatch(logOut());
  };

  return (
    <div>
      <h1>User Profile</h1>
      <p>Name: {user.name}</p>
      <p>Age: {user.age}</p>
      <p>Logged In: {user.loggedIn ? 'Yes' : 'No'}</p>

      {user.loggedIn ? (
        <button onClick={handleLogout}>Logout</button>
      ) : (
        <button onClick={handleLogin}>Login</button>
      )}
    </div>
  );
}

export default UserProfile;

다음 게시물에는 React Query(TanStack Query)에 대해 정리를 할 것이다.

profile
백엔드 주니어 개발자

0개의 댓글