티스토리 뷰

반응형

기존 Redux에서는 middleware를 사용하여 비동기 처리를 해야 했다. 안 그래도 복잡한 코드가 더 복잡해져 유지보수가 까다로워진다. Redux Toolkit은 간결한 코드로 비동기 처리를 쉽게 할 수 있다.

 

Redux와 Redux toolkit 비동기 처리 비교

구분 Redux Redux Toolkit
비동기 처리 도구 Middleware
- Redux Thunk
- Redux Saga
createAsyncThunk
액션 타입 정의 수동으로 정의해야 함 자동으로 생성됨
코드 구문 Boilerplate 코드가 많음 Redux보다 간결함
설치 및 설정 별도의 미들웨어 설치 및 설정이 필요 Redux Toolkit 패키지만 설치하면 따로 설치할 필요 없음
액션 생성 액션 생성자에서 직접 디스패치 createAsyncThunk에서 생성된 함수로 자동 디스패치
상태 업데이트 수동으로 상태 업데이트 자동으로 상태 업데이트 및 액션 타입에 따라 리듀서가 처리

 

Redux에서 Redux Thunk를 사용한 예제

const fetchUser = () => {
  return async (dispatch) => {
    dispatch({ type: 'FETCH_USER_REQUEST' });

    try {
      const response = await api.fetchUser();
      dispatch({ type: 'FETCH_USER_SUCCESS', payload: response.data });
    } catch (error) {
      dispatch({ type: 'FETCH_USER_FAILURE', payload: error.message });
    }
  };
};

Redux Toolkit에서 createAsyncThunk를 사용한 예제

// createAsyncThunk를 사용한 예제
import { createAsyncThunk } from '@reduxjs/toolkit';

export const fetchUser = createAsyncThunk(
    'user/fetchUser', // 리듀서이름/비동기함수이름
    async (userId) => {
      const response = await api.fetchUser(userId);
      return response.data;
});

 

 

Redux Toolkit 주요 기능

createAsyncThunk

비동기 작업을 처리하는 데 사용되는 함수를 생성한다. createSlide 내부에서 사용하며, 해당 비동기 작업에 대한 액션을 생성한다.

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

export const fetchUser = createAsyncThunk('user/fetchUser', async (userId) => {
  const response = await api.fetchUser(userId);
  return response.data;
});

 

pending, fullfilled, rejected

createAsyncThunk로 생성된 Thunk 함수의 세 가지 액션 상태다.

  • pending: 비동기 작업 진행 중
  • fullfiled: 비동기 작업 성공
  • rejected: 비동기 작업 실패
builder.addCase(asyncUserFetch.pending, (state, action) => {
  state.status = 'loading';
})
builder.addCase(asyncUserFetch.fulfilled, (state, action) => {
  state.status = 'complete';
  state.userList = action.payload;
})
builder.addCase(asyncUserFetch.rejected, (state, action) => {
  state.status = 'fail';
})

 

 

 

코드 예제

UserSlice.js

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"

// 비동기 action creator
export const asyncUserFetch = createAsyncThunk(
  'userSlice/asyncUserFetch',
  async () => {
    const res = await fetch("https://jsonplaceholder.typicode.com/users")
    const data = await res.json();
    return data
  }
)

const userSlice = createSlice({
  name: 'userSlice',
  initialState: {
    userList: [],
    status: null, // status 초기값
  },
  extraReducers: (builder) => {
    // 비동기 작업은 action creator를 자동으로 만들지 않기 때문에 extraReducers를 사용해서 action을 생성해야 한다.
    builder.addCase(asyncUserFetch.pending, (state) => {
      state.status = 'Loading';
    })
    builder.addCase(asyncUserFetch.fulfilled, (state, action) => {
      state.status = 'complete';
      state.userList = action.payload;
    })
    builder.addCase(asyncUserFetch.rejected, (state) => {
      state.status = 'fail';
    })
  },
})

export default userSlice;

 

store.js

import { configureStore } from "@reduxjs/toolkit";
import userSlice from "./userSlice";

// store 통합
const store = configureStore({
  reducer: {
    user: userSlice.reducer,
  }
})
export default store;

 

App.js

import './App.css';
import { Provider } from 'react-redux';
import UserList from './components/UserList';
import store from './store';

function App() {
  return (
    <Provider store={store}>
      <div className="App">
        <UserList />
      </div>
    </Provider>
  );
}

export default App;

 

UserList.js

import React, { useEffect } from 'react'
import { asyncUserFetch } from '../userSlice';
import { useDispatch, useSelector } from 'react-redux';

const UserList = () => {
  const dispatch = useDispatch();
  const userList = useSelector(state => state.user.userList);
  const status = useSelector(state => state.user.status);

  useEffect(() => {
    dispatch(asyncUserFetch());
  }, [dispatch]);
  
  return (
    <div>
      <ul>
        {
          status === 'Loading' ? (
            <div>Loading...</div>
          ) : userList && userList.map(user => (
            <li key={user.id}>
              <div>{user.name}</div>
            </li>
          ))
        }
      </ul>
    </div>
  )
}

export default UserList
반응형
반응형
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31