티스토리 뷰
[Next.js] getInitialProps에서 redux saga action이 dispatch가 완료 될때까지 멈추지 않는 이슈
심재철 2020. 4. 1. 20:02서론
프로젝트를 진행하다가 삽질한 내용을 공유합니다. Next.js에서는 getInitialProps라는 메소드가 있습니다. 이 메소드를 사용하면 화면이 렌더링 되기 전에 필요한 데이터를 미리 준비해 놓을 수 있습니다.
getInitialProps는 다음과 같은 상황에서 트리거 됩니다.
1. 주소창에 직접 URL을 치고 들어온 경우 SSR(Server Side Rendering)이 일어납니다. 이때 getInitialProps가 실행됩니다.
2. next/link나 next/router를 사용해서 클라이언트 사이드 라우팅(CSR)을 한 경우. 이 경우에도 getInitialProps가 실행됩니다.
이슈
제가 만들고 있는 프로젝트는 SNS라서 메인페이지에 진입했을때 피드의 리스트가 쭉 출력되어야 합니다. 그래서 메인페이지에 진입했을때 getInitialProps를 통해 서버사이드 렌더링을 하면서 필요한 데이터를 관련 액션을 dispatch해서 스토어가 업데이트 되면 그 업데이트 된 값을 다시 가져와서 컴포넌트로 내려주려고 했습니다. 아래와 같이 말이죠.
Index.getInitialProps = async ctx => {
await ctx.store.dispatch(createGetFeedsAction());
const feedState = ctx.store.getState();
return { feedState };
};
여기서 문제가 발생했습니다.
액션이 dispatch되고 나서 api호출을 통해 데이터를 가져와야 하는데 그 api 호출이 종료될때까지 await에서 블럭되는게 아니라 바로 다음줄로 넘어갑니다. 무슨 소리냐면
Index.getInitialProps = async ctx => {
console.log(1);
await ctx.store.dispatch(createGetFeedsAction());
console.log(2);
const feedState = ctx.store.getState();
return { feedState };
};
이런식으로 콘솔을 찍었을때 1이 출력되고나서 액션이 dispatch되서 스토어에 api 호출 결과가 담긴 다음에 2가 출력되어야 하는데 그게 아니라 1이 출력된다음에 바로 2가 출력되었습니다. await에서 제대로 블럭되지 않은거죠.
이 문제는 이렇게 해결했습니다.
const fetchAndWait = (
store: Store,
actionCreator: (...params: any[]) => ActionWithPayload,
params = [],
) =>
new Promise(resolve => {
store.dispatch(actionCreator(...params));
const unsubscribe = store.subscribe(() => {
const state = store.getState();
unsubscribe();
return resolve(state);
});
});
문제는 dispatch 함수의 호출 결과로 Promise를 리턴하지 않은거였습니다. await는 promise가 resolve될때까지 블럭 시키는 역할을 하는 키워드인데 제가 잠깐 그 사실을 망각하고 있었습니다. 그래서 fetchAndWait라는 유틸성 함수를 만들어서 액션을 dispatch하고 스토어에 상태가 업데이트 될떄까지 기다리고 업데이트된 상태를 resolve를 통해 promise 바깥으로 전달해줬습니다. 이제 다음과 같이 업데이트 된 상태를 getInitialProps에서 가져올 수 있게 되었습니다.
Index.getInitialProps = async ctx => {
const updatedStore = (await fetchAndWait(ctx.store, createGetFeedsAction)) as RootState;
const feedState = updatedStore.feed;
console.log(feedState);
return { feedState };
};
자 이제 업데이트 된 상태를 제대로 가져올 수 있게 되었습니다.
오픈소스가 아니어서 소스는 따로 공개하지 않습니다. 질문이 있으시면 댓글로 남겨주세요.
'Today I Learned' 카테고리의 다른 글
파이어베이스 프로젝트간 데이터 마이그레이션 하는 방법 (0) | 2021.04.04 |
---|---|
firebase에서 이미지 업로드시 이미지 경로 받아오기(download url, public url ) (0) | 2020.04.04 |
함수형 프로그래밍이란? (0) | 2020.03.25 |
스토리북을 효율적으로 관리하는 방법 (0) | 2020.03.23 |
브라우저 로딩 과정 (0) | 2020.03.20 |
- Total
- Today
- Yesterday
- server side rendering
- state
- Next.js
- useEffect
- props
- typescript
- rendering scope
- useRef
- return type
- webpack
- mobx
- hydrate
- reducer
- Action
- javascript
- reactdom
- react
- es6
- await
- atomic design
- design system
- Babel
- storybook
- promise
- Polyfill
- reflow
- type alias
- react hooks
- computed
- async
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |