728x90
//asyncActions.js

const { createStore, applyMiddleware } = require('redux');
const thunkMiddleware = require('redux-thunk').default;
const axios = require('axios');

const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST';
const fetchUsersRequest = () => ({
  type: FETCH_USERS_REQUEST,
});

const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS';
const fetchUsersSuccess = (users) => ({
  type: FETCH_USERS_SUCCESS,
  users,
});

const FETCH_USERS_ERROR = 'FETCH_USERS_ERROR';
const fetchUsersError = (error) => ({
  type: FETCH_USERS_ERROR,
  error,
});

const initialState = {
  loading: false,
  users: [],
  error: '',
};

const fetchUsers = () => {
  return function (dispatch) {
    dispatch(fetchUsersRequest());
    axios
      .get('https://jsonplaceholder.typicode.com/users')
      .then((res) => {
        const users = res.data.map((user) => user.id);
        dispatch(fetchUsersSuccess(users));
      })
      .catch((error) => {
        dispatch(fetchUsersError(error.message));
      });
  };
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_USERS_REQUEST:
      return {
        ...state,
        loading: true,
        users: [],
        error: '',
      };
    case FETCH_USERS_SUCCESS:
      return {
        ...state,
        loading: false,
        users: action.users,
        error: '',
      };
    case FETCH_USERS_ERROR:
      return {
        ...state,
        loading: false,
        users: [],
        error: action.error,
      };
    default:
      return state;
  }
};

const store = createStore(reducer, applyMiddleware(thunkMiddleware));
console.log('intial state : ' + store.getState());
const unsubscribe = store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch(fetchUsers());

기존 redux에서 async action처리를 위한 redux thunk middleware를 접목한 구현은 다음과 같다.

action을 직접 호출하는 대신 thunk를 호출하면 thunk 내에서 action을 호출하여 reducer에서 그에 맞는 state를 반영하는 개념이었다.

 

 

redux-toolkit도 크게 다르지 않다. redux와 크게 다르게 크게 명심해야할 점은 두가지가 있다.

  • thunk 내 action dispatch 불필요 및 action type 이름 자동 지정 (pending, fulfilled, rejected)
  • action에 대한 reducer를 extraReducers에 정의
// userSlice.js
const { createSlice } = require('@reduxjs/toolkit');
const { createAsyncThunk } = require('@reduxjs/toolkit');
const axios = require('axios');

//initial state
const initialState = {
  loading: false,
  users: [],
  error: '',
};

//thunk
const fetchUsers = createAsyncThunk('users/fetchUsers', () => {
  return axios.get('https://jsonplaceholder.typicode.com/users').then((res) => {
    return res.data.map((user) => user.id);
  });
});

//reducer
// redux thunk 내에서 지정된 type 이름의 action이 자동 dispatch =>  pending, fulfilled, rejected
const userSlice = createSlice({
  name: 'user',
  initialState,
  extraReducers: (builder) => {
    builder.addCase(fetchUsers.pending, (state) => {
      state.loading = true;
    });
    builder.addCase(fetchUsers.fulfilled, (state, action) => {
      state.loading = false;
      state.users = action.payload;
      state.error = '';
    });
    builder.addCase(fetchUsers.rejected, (state, action) => {
      state.loading = false;
      state.users = [];
      state.error = action.error.message;
    });
  },
});

module.exports = userSlice.reducer;
module.exports.fetchUsers = fetchUsers;
//index.js
const { configureStore } = require('@reduxjs/toolkit');
const userReducer = require('./userSlice');
const { fetchUsers } = require('./userSlice');

const store = configureStore({
  reducer: {
    user: userReducer,
  },
});

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch(fetchUsers());

+ Recent posts