Redux Middleware

Front-end/React 이론 스터디

Redux Middleware

조커린 2021. 6. 17. 12:35

Redux Middleware and Redux Thunk

리덕스의 미들웨어는 액션이 디스패치되어서 리듀서에서 이를 처리하기 전에 사용할 수 있는 것들을 사전에 설정해서 사용할 수 있게 해줍니다.
applyMiddleware 를 이용해 등록하여 사용할 수 있습니다.

리덕스 미들웨어의 기본 템플릿

const middleware = (store) => (next) => (action) => {
  //do something
};

위의 템플릿은 하단의 예제와 같습니다 . 함수를 연달아 리턴해주는 함수를 화살표 함수로 나타낸 것입니다.

function middleware(store) {
  return function (next) {
    return function (action) {
      // 하고 싶은 작업...
    };
  };
}
  • store : 리덕스 스토어 인스턴스 (dispatch, getState, subscribe 들어있음)
  • next : 액션을 다음 미들웨어에게 전달하는 함수 next(action)의 형태.
    다음 미들웨어가 없다면 리듀서에게 액션을 전달해준다. 만약에 next를 호출하지 않게 된다면 액션이 무시처리되어 리듀서에게로 전달되지 않습니다.
  • action : 현재 처리하고 있는 액션 객체

const myLogger = (store) => (next) => (action) => {
  console.log("state = ", store.getState());
  const result = next(action); // 다음 미들웨어에게 액션을 전달한다.

  // 업데이트 이후의 상태를 조회하기
  console.log("\t", store.getState());
  console.log("action = ", action.type);
  return result; //dispatch(action)의 결과물이 될 값.
};

이렇듯 미들웨어를 수동으로 만들어 줄 수 있고 액션이 함수타입일때 이를 실행시키게끔 만들어 줄 수도 있습니다.

const thunk = (store) => (next) => (action) => {
  typeof action === "function"
    ? action(store.dispatch, store.getState)
    : next(action);
};

Redux-Logger 를 통해 로깅하기

리덕스 관련 값들을 콘솔에 로깅하는 건 직접 만들기보다는 redux-Logger를 이용하는 것이 좋습니다.
적용시 applyMiddleware의 마지막 파라미터로 넣어주어야 합니다.

composeWithDevTools :redux-devtools 와 함께 사용하기 위한 것인데, 사용시에는 파라미터로 applyMiddleware를 한 번 감싸줍니다.

npm install redux-logger

LogRocket/redux-logger

const store = createStore(
  rootReducer,
  composeWithDevTools(applyMiddleware(middleware1, middleware2, logger)) // react dev tools와 함께 사용할 때
);

ReactDOM.render(
  <BrowserRouter>
    <Provider store={store}>
      <App />
    </Provider>
  </BrowserRouter>,
  document.getElementById("root")
);

logger 를 사용하면 이런 식으로 action과 state값을 받을 수 있습니다.
devtools와 사용하면 이전 상태와 이후의 상태도 함께 보면서 logging할 수 있습니다.

Redux-thunk

리덕스에서 액션을 리턴할 때 객체가 아니라 함수를 리턴할 수 있게 해주어, 함수의 형태일때 그 함수를 실행하고, 객체가 되었을 때, reducer로 dispatch하게 해주는 미들웨어.

dispatch를 인수로 받아 객체 대신 함수를 생성하는 액션 생성함수를 작성할 수 있게 해줍니다.

예를 들면, 1초뒤 특정 액션을 실행하게 하는 함수를 만들고 싶으면 이렇게 increaseAsync과 같은 함수를 작성하게 된다면 1초 뒤에 INCREMENT_COUNTER 액션이 1초 뒤에 디스패치 됩니다.

const INCREMENT_COUNTER = "INCREMENT_COUNTER";

function increment() {
  return {
    type: INCREMENT_COUNTER,
  };
}

function incrementAsync() {
  return (dispatch) => {
    // dispatch 를 파라미터로 가지는 함수를 리턴합니다.
    setTimeout(() => {
      // 1 초뒤 dispatch 합니다
      dispatch(increment());
    }, 1000);
  };
}

또한 특정 조건에 따라 액션을 디스패치하거나 무시하는 코드를 작성할 수도 있습니다.

function incrementIfOdd() {
  return (dispatch, getState) => {
    const { counter } = getState();

    if (counter % 2 === 0) {
      //getState를 파라미터로 받아 스토어의 상태에 접근 해 현재 스토어 상태의 값에 따라 액션이 dispatch될 지, 무시될 지 정해줄 수 있다.

      return;
    }

    dispatch(increment());
  };
}

데이터 패칭시 redux-thunk의 사용

프로미스를 다루는 리덕스 모듈을 다룰 때..

  1. 프로미스가 시작, 성공, 실패했을 때 다른 액션을 디스패치 해야합니다.
  2. 각 프로미스마다 thunk 함수를 만들어 주어야 합니다.
  3. 리듀서에서 액션에 따라 로딩중, 결과, 에러상태를 변경해주어야 합니다.

dispatch 시에 파라미터를 비동기함수로 넣어 redux-thunk에서 함수가 파라미터임을 감지하여 해당 함수를 실행합니다.
성공적으로 데이터 패칭이 된다면 성공시 액션을 실행하고, 실패하게 된다면 실패시 수행할 액션을 실행합니다.

하단의 API 요청을 하는 예시처럼 주로 쓰입니다.

참고 : https://medium.com/humanscape-tech/redux%EC%99%80-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4-thunk-saga-43bb012503e4

// action.js
const loginSuccess = (response) => {
  return {
    type: "LOGIN_SUCCESS",
    payload: response,
  };
};

const loginFail = (error) => {
  return {
    type: "LOGIN_FAIL",
    payload: error,
  };
};

const loginTry = (someValue) => async (dispatch, getState) => {
  dispatch({ type: "LOGIN_REQUEST" });
  try {
    const response = await myAjaxLib.post("/someEndpoint", { data: someValue });
    dispatch(loginSuccess(response));
  } catch (error) {
    dispatch(loginFail(error));
  }
};

이런 방식으로 dispatch와 getState 를 파라미터로 가지게 되어 상황에 맞추어 dispatch를 리턴하게 됩니다.
상황에 따라 복잡해지게 될 때는 saga미들웨어와 쓰이게 된다고 합니다.

'Front-end > React 이론 스터디' 카테고리의 다른 글

Constate, Recoil  (0) 2021.06.11
API Fetching을 Context와 함께 써보자.  (0) 2021.06.04
CSS Module  (0) 2021.05.31
Context API  (0) 2021.05.29
useCallback  (0) 2021.05.26