1. 미들웨어가 디스패치 앞뒤에 코드를 추가할 수 있게 해준다.
2. 미들웨어가 여러개면 미들웨어가 순차적으로 실행된다.
3. 디스패치 메소드를 통해 store 로 가는 액션을 가로챌 수 도 있고 변조를 할 수 도 있다.

const store = createStore(reducer, composeWithDevTools(applyMiddleware()));

액션 -> 미들웨어 -> 리듀서 -> 스토어

미들웨어의 종류로는
Redux-Thunk
Redux-Saga
function middleware1(store) {
  console.log("middleware1", 0);
  return (next) => {
    console.log("middleware1", 1, next);
    return (action) => {
      console.log("middleware1", 2);
      const returnValue = next(action);
      console.log("middleware1", 3);
      return returnValue;
    };
  };
}

function middleware2(store) {
  console.log("middleware2", 0);
  return (next) => {
    console.log("middleware2", 1, next);
    return (action) => {
      console.log("middleware2", 2);
      const returnValue = next(action);
      console.log("middleware2", 3);
      return returnValue;
    };
  };
}

const store = createStore(
  reducer,
  composeWithDevTools(applyMiddleware(middleware1, middleware2))
);

action 을 dispatch 시킬 때마다
middleware1 2
middleware2 2
middleware2 3
middleware1 3
순으로 찍힌다. 최종적으로는 middleware1 의 returnValue 가 반환된다.