Redux Saga 파헤치기

원지렁·2023년 9월 17일
0
post-thumbnail

시작하며

SortingBars 프로젝트를 진행하면서 랜덤한 값을 모아놓은 배열 데이터에 대한 상태를 한번 다뤄본게 Redux에 대한 최초의 경험이었다.

이후 데이터를 다루는 과정에서 비동기적으로 API 요청을 통해 처리해야하는 일들이 대다수였고 이러한 작업을 좀 더 정확하고 유용하게 만들어주는 Redux Saga Middleware에 대해 공부하게 되었다.

1. Saga 작동 방식

Redux Saga 작동로직에 대한 이미지를 찾아보며 아래와 같이 보기 쉽게 정리해보았다.

1 & 2: UI event 발생
3: Redux Action 작동
4: dispatch Action
5 & 6: API Call
7: 상태값 Store 저장
8: 상태값 업데이트 및 UI 업데이트

2. 예시 코드

React와 Redux Saga를 이용하여 만들었던 서버에 데이터를 요청하는 fetchData에 대한 예시를 소개해보고자 한다.

코드 작동방식

1. UI의 특정 이벤트(예: 첫 화면 렌더링)로 인한 액션 dispatch
2. Saga 액션 감지 (take/takeLatest 등)
3. Saga에서의 비동기 작업(예: API 호출) 수행
4. 비동기 작업 완료 후, Saga의 새로운 액션 dispatch(예:put)를 통한 Redux store 업데이트
5. 해당 액션에 응답하여 Reducer 실행되어 상태가 업데이트 됨
6. 상태가 변경됨에 따른 React 컴포넌트 리렌더링
  • App.js
import React, { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
  fetchData,
} from "./redux/actions/data;
import ContentList from "./components/ContentList";

function App() {
  const dispatch = useDispatch();
  const dataList = useSelector((state) => state.data.dataList);
  // 생략...
  
  useEffect(() => {
    dispatch(fetchData());
  }, []);
  
  return (
    <>
      // 생략...
      <ContentList
        dataList={dataList}
      />
    </>
  );
}
  • dataActions.js
// Action Types
export const FETCH_DATA = "FETCH_DATA";
export const SET_DATA = "SET_DATA";
export const API_ERROR = "API_ERROR";

// Action Creators
export const fetchData = () => ({
  type: FETCH_DATA,
});

export const setData = (data) => ({
  type: SET_DATA,
  payload: data,
});

export const apiError = (error) => ({
  type: API_ERROR,
  payload: error,
});
  • dataReducer.js
import {
  SET_DATA,
  API_ERROR,
} from "../../actions/data";

const initialState = {
  dataList: [],
  error: null,
};

const dataReducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_DATA:
      return { ...state, dataList: action.payload };
    case API_ERROR:
      return { ...state, error: action.payload };
    default:
      return state;
  }
};

export default dataReducer;
  • dataSagas.js
import { call, put, takeLatest } from "redux-saga/effects";
import axios from "axios";
import {
  FETCH_DATA,
  setData,
  apiError,
  fetchData,
} from "../../actions/data";

function* fetchDataSaga() {
  try {
    const response = yield call(axios.get, 'fetchdata_server_url', {
      headers: {
        "Content-Type": "application/json",
      }
    });

    yield put(setData(response.data));
  } catch (error) {
    yield put(apiError(error));
  }
}

export default function* dataWatcher() {
  yield takeLatest(FETCH_DATA, fetchDataSaga);
}

마치며

이로써 비동기 작업을 진행할 때 좀 더 유용하고 명확한 방식으로 상태관리를 하는법에 대해 한발짝 더 다가가게 되었다.

다만 모든 방법들이 그렇듯 완벽한 방법은 없고 프로젝트와 상황에 맞게 더 효율적인 방법을 끊임없이 연구 해봐야한다. 그래도 직접 상태관리를 다뤄볼 경험이 그동안은 많지 않았는데, 직접 경험해보며 점점 익숙해져 나가는 것부터 의의를 두는 중이다.

비동기 통신과 상태관리를 마스터하는 그날까지 포스팅을 보는 분들이 도움이 되시길 바라며...
모든 코린이 분들 화이팅!

profile
새싹 개발자 지렁이의 벨로그입니다.

0개의 댓글