NEXT.js의 Dynamic routing을 이용한 비동기 통신

YU YU·2021년 8월 14일
3
post-custom-banner

👉이 글을 읽으면 좋은 사람

'동적 라우팅을 통해서 받은 값으로 비동기통신을 하고 싶고, 그로 인한 결과를 화면에 뿌려주고 싶다!'라고 생각하는 사람

이번에 어플을 만들면서 동적라우팅으로 모든 것을 해결하려고 했다.
여기서부터 모든 문제가 발생했고, 시간이 오래 걸리는 문제가 발생했다.
여기서 내가 경험했던 NEXT.js의 동적라우팅을 사용하면 생기는 문제점과 해결법을 적어보겠다.(미래의 나를 위해서)

실제로 저렇게 생각을 하고 동적라우팅을 생각해서 코드를 작성했다.

const {id} = router.req만 알면 된다고?

👉NEXT.js의 고질적인 reload문제


여기서 각 항목 테스트를 누르면
<button onClick={() => router.push('/test/1-1')}>테스트테스트</button>
을 통해 http://testcollector.shop/test/1-1로 가게끔 설정을 했다.

test폴더 안에 동적라우팅을 하는 페이지를 넣어주었다.
이 페이지 안에

이렇게 설정을 해주면 first에는 주소창에 url주소/test/1-1라고 하면 '1-1'의 값이 들어가는 것이다.

이제 이러한 생각이 들 것이다.

first에는 이제 router.query에 해당하는 값이 넣어지겠구나!


하지만, 실체는 2번 렌더링 되면서,
first의 값은 'undefined'였다가 '1-1'의 값이 된다.

별 문제가 없어보인다. 그러나 이것은 큰! 문제가 된다.

왜냐하면 이 변수값으로 axios나 fetch를 이용한 비동기 통신을 할 때 [first]의 값을 받아야 하는데 못받기 때문이다.

result = axios.post(`http://url/test/${first}`)
이러한 코드 말이다.



그래서 나는 useEffect를 쓰기로 하였다.

const result;
useEffect(async()=>{
  result = axios.post(`http://url/test/${first}`)  
},[first])

이렇게 쓰면 result의 값이 undefined이 되었다가 데이터 값을 받기에 다 괜찮아질 줄 알았다.
그런데...
useEffect자체가 비동기가 되는게 아니다보니까 저기서 result가 나오기 전에 이미 return이 실행되서 result를 이용해서 렌더링을 마치기 때문에 return 구문 안에 저기서 사용되는 변수값을 넣어주면 '오류'가 뜬다.....ㅠㅠ

동적라우팅을 하면 NEXT.js는 reload가 된다.

구조적인 문제였다... 나말고도 많은 사람들이 찾아보았다. NEXT.js dynamic routing의 문제였다.

😀해결책

처음 링크로 가는 버튼에

<Link href={`/test/[first]?first=1-1`} as ={`/test/1-1`}>

이러한 식으로 적어주면 페이지가 reload가 되지 않고 한번에
const {first} = router.req의 값이 '1-1'이 된다.

😖또 다른 문제점

'이제 useEffect를 안써도 된다!'는 기쁨도 잠시다.
페이지 전체를 그리는 함수에는 async를 못단다.... 이건 await를 써야하는데 ㅠㅠ
그러면 async를 쓰기 위해 다시 useEffect를 써야하는데... 못받아도 계속 코드는 진행되니 미칠 노릇이다. ㅠㅠㅠ

getServerSideProps의 재앙

또 다른 문제점의 해결책을 찾던 중 redux에서 배운 middleware를 쓰면 어떨까 생각했지만 그러려면 폴더 구조를 바꿔야해서 힘들 것 같았다. 심지어 나 혼자서 개발하는 것도 아닌데...

그러던 중 getInitialProps를 발견했다!
NEXT.js의 getInitialProps 문서
이걸 타고 들어가보니 getServerSideProps를 발견할 수 있었다.


비동기 통신을 이용한 값을 써야할 때 쓰는 함수이다. 컴포넌트가 실행되기 전에 실행해서 객체값을 props값에 담아 return하는 함수이다.

비동기통신!
이거야말로 내가 찾던 거였다.

{params}자리에는 여러가지 인잣값을 받을 수 있다.
params를 쓰면 아까 썼던 router.query의 값이랑 똑같은 값을 얻을 수 있다.

router.query={first:'1-1'}
params = {first:'1-1'}

자세한 건 NEXT.js 공식홈페이지에서 알아보자.

여기에

function Page({ data }) {
return(
<>{data}</>)
}

export async function getServerSideProps() {
	const res = await axios.post(`https://.../data`);
	const data = res.data;
	console.log(data);
	return { props: { data } }
}

export default Page

를 썼지만 화면에는 아무것도 나오지 않았다. 심지어 {data.id}를 Page 에서 return 값에 쓸때는 data.id값이 없다며 오류가 난다...
웃긴건 getServerSideProps()에서의 data값은 잘 출력이 되었다....

혹시 몰라서 다음과 같이 바꿔보았다.

function Page({ props }) {
return(
<>{props}</>)
} ...

Page함수에서 props값을 인식을 못했다. props=undefined인 상태이다.
사람들은 잘 되는 것 같았다....ㅠㅠ 왜 나만 안돼 ㅠㅠ

😂원인

__app.js파일에서 context,reducer을 쓰려 설정한 부분에서

<Store.Provider value={{state,dispatch}}>
          <Component/>
</Store.Provider>

이렇게 쓴 것이 문제였다. props값을 넘겨주는 부분이 없다.

😀해결책

<Store.Provider value={{state,dispatch}}>
          <Component {...pageProps}/>
</Store.Provider>

이렇게 바꾸어주면 getServerSideProps를 써서 얻은 값도 props값에 담겨 잘 넘겨져서 드디어 비동기통신으로 얻은 값을 사용할 수 있다.

getServerSideProps를 쓰면 가장 먼저 실행되고, async함수여서 비동기 통신으로 값을 받아올때까지 기다리기에 받은 데이터값을 화면에 뿌려줄 수 있다!

profile
코딩 재밌어요!
post-custom-banner

0개의 댓글