redux-thunk

fe_sw·2022년 8월 25일
0

Redux

목록 보기
3/5
post-thumbnail

redux-thunk

리덕스를 사용하는 어플리케이션에서 비동기 작업을 처리 할 때 가장 기본적인 방법으로는 redux-thunk 라는 미들웨어를 사용하는것입니다.

이 미들웨어는 비동기 작업을 다룹니다. 이를 사용하여 비동기 작업을 관리하는건 매우 직관적이고 간단하다.

미들웨어

// dispatch 와 reducer사이에 동작하는게 미들웨어다.
// 매개변수3개가들어가는 함수, 밑에처럼 사이사이에 함수를 실행할 필요가 없는경우

const firstMiddleware = (store) => (dispatch) => (action) => { //미들웨어 예시1
  console.log('first-middleware-로깅 시작', action);
  dispatch(action); //dispatch + console기능이 추가된 미들웨어임
  console.log('first-middleware-로깅 끝');
};

redux-thunk 구조

// 들어오는 객체가 함수면 비동기처리를 하고 , 객체면 동기처리를 수행한다
const thunkMiddleware = (store) => (dispatch) => (action) => {/
  if (typeof action === 'function') { //함수면 -> 비동기로 처리
    return action(store.dispatch, store.getState); //함수실행
  }
  return dispatch(action); //객체면->동기처리
};

액션생성함수도 객체,함수에 따라 구분해서 만든다.

비동기 액션함수일경우 return값을 객체가아닌 함수를 리턴한다. setTimeout같은 비동기처리안에서 동기적인 action을 dispatch하는 구조다.

//비동기 액션(함수) creator
const logIn = (data) => { 
  return (dispatch, getState) => { // async action -> 동기액션크리에이터와 다르게 함수를 리턴
    dispatch(logInRequest(data)); //로그인요청
    try {
      setTimeout(() => {
        dispatch(logInSuccess({ //로그인성공 // 비동기작업 환경에서 동기작업을 함
          userId: 1,
          nickname: 'seok'
        }));
      }, 2000);
    } catch (e) {
      dispatch(logInFailure(e));//로그인실패
    }
  };
};
//동기 액션크리에이터
const logInRequest = (data) => {
  return {
    type: 'LOG_IN_REQUEST',
    data,
  }
};
//동기 액션크리에이터
const logInSuccess = (data) => {
  return {
    type: 'LOG_IN_SUCCESS',
    data,
  }
};
//동기 액션크리에이터
const logInFailure = (error) => {
  return {
    type: 'LOG_IN_FAILURE',
    error,
  }
};
//동기 액션크리에이터
const logOut = () => {
  return { // action
    type: 'LOG_OUT',
  };
};

실행

store.dispatch(logIn({ //로그인요청(비동기처리->thunk작동)
  id: 1,
  name: 'seok',
  admin: true,
}));

redux-thunk 라이브러리 사용

// index.js

import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './modules';
import logger from 'redux-logger';
import ReduxThunk from 'redux-thunk';

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(ReduxThunk, logger)) // logger 를 사용하는 경우, logger가 가장 마지막에 와야합니다.
); // 여러개의 미들웨어를 적용 할 수 있습니다.

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
// actions//counter.js

// 액션 타입
const INCREASE = 'INCREASE';
const DECREASE = 'DECREASE';

// 액션 생성 함수
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });

// getState를 쓰지 않는다면 굳이 파라미터로 받아올 필요 없습니다.
export const increaseAsync = () => dispatch => {
  setTimeout(() => dispatch(increase()), 1000);
};
export const decreaseAsync = () => dispatch => {
  setTimeout(() => dispatch(decrease()), 1000);
};

// 초깃값 (상태가 객체가 아니라 그냥 숫자여도 상관 없습니다.)
const initialState = 0;

export default function counter(state = initialState, action) {
  switch (action.type) {
    case INCREASE:
      return state + 1;
    case DECREASE:
      return state - 1;
    default:
      return state;
  }
}

// CounterContainer.js

import React from 'react';
import Counter from '../components/Counter';
import { useSelector, useDispatch } from 'react-redux';
import { increaseAsync, decreaseAsync } from '../modules/counter';

function CounterContainer() {
  const number = useSelector(state => state.counter);
  const dispatch = useDispatch();

  const onIncrease = () => {
    dispatch(increaseAsync());
  };
  const onDecrease = () => {
    dispatch(decreaseAsync());
  };

  return (
    <Counter number={number} onIncrease={onIncrease} onDecrease={onDecrease} />
  );
}

export default CounterContainer;

0개의 댓글