⚛️React | Redux로 상태 관리하기 & 상태 업데이트하기

dayannne·2023년 9월 15일
0

React

목록 보기
3/13
post-thumbnail

✨ 시작하며

Redux는 데이터의 상태 관리를 용이하게 만드는 라이브러리 중 하나이다.
조금더 세팅을 간편하게 하고 사용할 수 있는 Recoil도 있지만 현업에서 사용한다고 들었기에 현재 만들고 있는 TypeScript 언어를 사용 중인 프로젝트에 한번 적용하며 공부해 보고자 했고 그 과정을 정리해 보려 한다


1. 설치하기

Redux를 사용하기 위해 먼저 ReduxRedux Toolkit을 설치한다.

npm install @reduxjs/toolkit react-redux

2. 상태와 액션 정의

Redux에서는 상태(state)와 액션(action)을 정의하여 애플리케이션의 상태를 관리한다.
상태는 애플리케이션의 데이터를 저장하고, 액션은 상태를 변경하는 요청이다. 프로젝트에서 상품 상세 페이지에 나타나는 '상품 상세정보 데이터'를 상태관리 하기 위해 아래와 같이 Redux를 사용했다.

1) 초기 상태 정의하기

import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit';
import { urlApi } from 'src/api/axiosInstance';

// API로 받아 올 상품 데이터의 타입 정의
interface ProductData {
  product_id: number;
  created_at: string;
  updated_at: string;
  image: string;
  product_name: string;
  price: number;
  shipping_method: string;
  shipping_fee: number;
  stock: string;
  products_info: string;
  seller: number;
  store_name: string;
}

// 상태의 타입 정의
interface ProductState {
  productData: ProductData | null; // 상품 데이터
  error: null | any; // 오류 메시지
  loading: boolean; // 로딩 상태
}

// 초기 상태 정의
const initialProductState: ProductState = {
  productData: null,
  error: null,
  loading: false,
};

2) 비동기 데이터 가져오기

액션을 정의하는 데에 사용할 비동기 작업을 처리하기 위해 Redux에서는 createAsyncThunk 함수를 사용한다. 이를 통해 API 호출과 같은 비동기 작업을 쉽게 관리할 수 있다. 아래와 같이 axios로 세팅한 axiosInstance를 가져와 상품 상세정보 데이터를 불러 왔다.

export const getProductData = createAsyncThunk<ProductData, number>(
  '/product/getProduct',
  async (postId) => {
    const res = await urlApi.get(`/products/${postId}/`);
    return res.data;
  },
);

3) 액션 정의하기

// 액션 생성자 함수를 사용하여 액션 정의
export const setProductData = createSlice({
  name: 'product',
  initialState: initialProductState,
  reducers: {
    // setProductData 액션
    setProductData: (state, action: PayloadAction<ProductData | null>) => {
      // 상태의 productData를 업데이트
      state.productData = action.payload;
    },
  },
  // 비동기 작업에 대한 액션은 extraReducers에 정의
  extraReducers: (builder) => {
    builder
      .addCase(getProductData.pending, (state) => {
        // API 요청이 보류 중일 때 상태 업데이트
        state.error = null;
        state.loading = true;
      })
      .addCase(
        getProductData.fulfilled,
        (state, action: PayloadAction<ProductData>) => {
          // API 요청이 성공하면 상태 업데이트
          state.error = null;
          state.loading = false;
          state.productData = action.payload;
        },
      )
      .addCase(getProductData.rejected, (state, action: PayloadAction<any>) => {
        // API 요청이 실패하면 상태 업데이트
        state.error = action.payload;
        state.loading = false;
      });
  },
});

// 액션 생성자 함수 내보내기
export const { setProductData } = productSlice.actions;

// 리듀서 내보내기
export default productSlice.reducer;

3. 불러오기 & 상태 업데이트하기

이렇게 상태와 액션에 대한 Redux 세팅을 마치고, 상태를 업데이트할 때에는 디스패치(dispatch)를 사용한다. 저장한 '상품 상세정보 데이터'를 각 상품 상세 페이지마다 갱신해 불러오기 위해 다음과 같이 코드를 작성했다.

import { useDispatch, useSelector } from 'react-redux';
dispatch(setProductData(productData));

...
const productId = location.state;
const dispatch = useDispatch<any>();
const productData = useSelector(
    (state: RootState) => state.product.productData,
);

const loading = useSelector((state: RootState) => state.product.loading);

  useEffect(() => {
    dispatch(getProductData(productId));
  }, [productId]);
  1. import 문:
    react-redux 패키지에서 useDispatchuseSelector 훅 불러오기
  2. const dispatch = useDispatch();:
    useDispatch 훅을 사용하여 Redux 스토어에 접근하고, dispatch 함수를 얻는다.
  3. const productData = useSelector(...)
    useSelector 훅을 사용하여 Redux 스토어에서 상품 데이터를 가져온다.
  4. const loading = useSelector(...):
    useSelector 훅을 사용하여 Redux 스토어에서 loading 상태를 가져온다. 이는 비동기 작업 진행 상태를 나타낸다.
  5. useEffect:
    컴포넌트가 마운트될 때, productId가 변경될 때마다 dispatch(getProductData(productId))를 호출한다. 이를 통해 getProductData 액션을 디스패치하고, 결과적으로 Redux를 통해 상품 데이터를 비동기적으로 가져온다.

결과적으로 프로젝트에는 상태마다 작성하는 useEffect의 사용과 코드 수를 조금 더 줄여보고자 React-query를 도입하기로 하면서 React-query와 조금더 잘 맞는 Recoil로 변경하기로 했지만,
다른 데이터들도 Redux로 세팅해 보면서 Redux를 조금이나마 익혀보고 공부해볼 수 있었기에 나중 다시 사용하게 될 때를 위해 기록을 남겨 본다!

profile
☁️

0개의 댓글