May 17th 2019
Contents
Redux Middleware는 action creator로 생성한 action이 거쳐가는 함수입니다.
Middleware 함수는 action을 전달 받은 후, 해당 middleware가 관심이 있는 action이라면 함수 내에 정해놓은 어떠한 행동이 취해지고, 그렇지 않다면 NEXT middleware로 전달합니다. 이렇게 여러 개의 middleware가 실행될 수 있습니다. 그렇다면 실제 비동기 middleware를 어떻게 동작하는지 알아보며 실제 구현을 해 보도록 하겠습니다.
우리가 만들 async middleware는 전달 받는 action이 promise인지 아닌지 확인을 합니다. 만약 promise가 우리의 async middleware가 관심이 있는 action이 아니기 때문에 바로 next 함수를 실행합니다. 하지만, promise라면 전달 받은 promise가 resolve될 때까지 기다립니다.
그리고 비동기 후 전달 받은 데이터를 payload로 한 새로운 action을 생성하고 다시 모든 middleware에 거쳐갈 수 있도록 합니다. 새로운 acion을 생성하는 이유는 비동기로 전달 받은 데이터가 다른 middleware 함수에서 검토를 필요로 할 수도 있기 때문입니다.
Redux Middleware의 Syntax는 함수가 연달아 두 개의 함수를 반환하는 구조입니다. 구조가 이렇게 짜여진 특별한 이유는 없는것 같으며, Redux 저자의 의도로 이러한 구조로 만들어 졌습니다. 맨 상위의 함수의 argument 중에서는 dispatch를 destructuring 했으며, 두번째, 세번째 함수에서 다음 middleware로 넘기는 next 함수와 action을 인자로 받습니다.
// Redux Middleware Syntax
export default ({ dispatch }) => next => action => {};
이제 위 syntax를 이용해 aysnc middleware를 작성해 봅시다. 먼저 전달받은 action의 payload 속성으로 promise가 들어왔는지 아닌지 확인을 합니다. 만약 promise라면 resolve 될 때까지 기다리고, 그렇지 않으면 해당 middleware와 관련이 없는 action이기 때문에 다음 함수로 넘어가는 next 함수를 호출합니다.
export default ({ dispatch }) => next => action => {
if (!action.payload || !action.payload.then) {
return next(action);
}
action.payload.then(response => {
const newAction = {
...action,
payload: response
};
dispatch(newAction);
});
};
만약 Redux store의 state를 schema 또는 type과 관련된 관점으로 본다면 우리는 state의 특정 속정의 값으로 일정한 타입의 값을 받기를 원할 것입니다. 왜냐하면 의도하지 않은 값이 state로 할당이 된다면, 앱의 작동이 원활하지 않거나 의도하지 않은 결과를 얻을 수 있기 때문입니다. 따라서, 개발환경에서 작업을 하다 위와 같이 의도치 않은 값이 state로 할당이 된다면, 우리가 인지할 수 있도록 도와주는 middleware를 만들어 작업할 수도 있습니다.
JSON은 데이터를 교환하고 저장하는 방식이며 JSON Schema는 이 JSON 데이터의 형식을 기술한 문서입니다. JSON Schema(link: http://json-schema.org/}의 Validation을 이용하면, 우리의 JSON 데이터가 유효한지 아닌지 확인할 수 있습니다. JSON Schema를 이용해 우리의 Redux store의 state 값이 유효한지 확인하는 middleware를 만들어 보도록 하겠습니다.
이 middleware의 기능은 state의 값이 변경된 후 변경된 state가 유효한지 확인하는 것입니다. 따라서, middleware 함수가 처음 실행되고 전달받은 action은 다음 middleware로 그대로 흘려보냅니다.
export default ({ dispatch }) => next => action => {
next(action);
};