
Nuxt는 Vue.js의 서버사이드 렌더링을 지원하기 위한 프레임워크로써, Vue.js SPA에서 데이터를 호출하는 방식과 다르게 비동기 데이터 호출을 위한 Hook이 따로 존재합니다. 이번 포스트에서는 그 Hook인 fetch와 asyncData Hook에 대해 살펴보겠습니다.
fetch & asyncData
일단 공식문서의 간략한 설명을 번역하면 아래와 같다.
fetchhook (Nuxt 2.12+)은 모든 컴포넌트에서 사용할 수 있고, (client-side 렌더링 중) 렌더링이 진행중인 상태와 에러에 대한 참조(shortcuts)를 제공합니다.asyncData은 오직 page 컴포넌트에서만 사용할 수 있습니다.fetch와 다르게 client-side 렌더링 중 로딩 placeholder를 표시할 수 없습니다: 대신에, 이 hook이 완료될때까지 route navigation을 막으며 실패했을 경우 페이지에 에러를 표시합니다.
아직 두개의 hook에 대해 너무나도 간략한 설명이기에 더 자세히 해보겠습니다.
fetch
fetch는 컴포넌트 인스턴스가 생성된 후 server-side 렌더링 동안 또는 client-side에서 네비게이션 되는 동안 호출되는 hook으로, 비동기 데이터 호출이 완료되었을때 (async/await를 사용) promise를 반환합니다.
- 초기 페이지가 렌더링 될때 서버사이드에서 호출
- 컴포넌트가
mounted된 후 클라이언트에서 호출
fetch hook은 컴포넌트 레벨에서 아래의 property와 함께 $fetchState와 함께 노출됩니다.
pending은Boolean값으로 client-side 에서fetchhook이 호출되었을때 placeholder를 표시하도록 해줍니다.error는null또는 fetch hook이 반환한Error입니다.timestamp는 최신 fetch의 timestamp로써,keep-alive으로 caching 하는 것에 유용합니다.
Nuxt에 의해 fetch가 호출되는 것이외에도 컴포넌트에서 수동으로 this.$fetch()를 호출해 fetch를 사용할 수도 있습니다.
1 | <template> |
Option
fetchOnServer:BooleanorFunction(기본값:true)이며 server-rendering 중에fetch()를 호출할지 설정할 수 있습니다.fetchDelay:Integer(기본값:200)이며 millisecond 단위로 최소 실행시간을 설정할 수 있습니다.
fetchOnServer가 false 또는 false를 반환할 경우, fetch는 오직 client-side에서만 호출될 것이며 $fetchState.pending은 컴포넌트가 server-rendering일때 true를 반환할 것입니다.
1 | export default { |
querystring 변경 감지하기
fetch hook은 기본적으로 querystring 변경시 호출되지 않는다. 이를 위해 $route.query를 관찰해 $fetch를 호출해야합니다.
1 | export default { |
캐싱
<nuxt/>과 <nuxt-child/> 컴포넌트에서 이미 방문했던 페이지의 fetch 호출을 절약하기 위해 keep-alive 디렉티브를 사용할 수 있습니다.
1 | <template> |
또한, <nuxt> 컴포넌트에 keep-alive-props prop을 전달함으로써 <keep-alive>에 전달될 props를 명시할 수 있습니다.
1 | <nuxt keep-alive :keep-alive-props="{ max: 10 }" /> |
메모리상 오직 10개 페이지 컴포넌트만 유지할 수 있습니다.
activated hook 사용하기
Nuxt는 (ssr을 포함한) 가장 최신의 fetch 호출에 대한 this.$fetchstate.timestamp를 직접 채웁니다. fetch에 30초 캐시를 추가하기 위해 activated hook을 혼합해 fetch property를 사용할 수 있습니다.
1 | <template> ... </template> |
마지막 fetch 호출이 30초 전이었다면, 동일 페이지 내 navigation은 fetch를 호출하지 않을 것입니다.
Async Data
asyncData는 오직 pages 안에서만 사용가능하고 이 hook 안에서는this객체에 접근할 수 없습니다.
asyncData는 universal nuxt app의 비동기 데이터 호출을 위한 또 다른 hook으로, fetch와 다르게 컴포넌트 인스턴스에서 비동기 state를 저장하기 위한 property를 설정해줘야 합니다(또는 Vuex actions의 dispatch). asyncData는 간단하게 컴포넌트의 지역 state에 반환된 값을 병합(merge)합니다.
1 | <template> |
fetch와 다르게 route transition 동안 asyncData가 완료되고 promise를 반환합니다. 이것이 의미하는 바는 client-side transitions 동안에는 로딩 placeholder(loading placeholder)는 보여지지 않는다는 것입니다 (비록 유저에게 진행상태를 알려주기 위해 진행바를 사용할 수 있을지라도). 대신에 Nuxt는 다음 페이지로 navigation 되기 전 완료되거나 에러 페이지를 보여줄때까지 asyncData hook을 기다립니다.
asyncData hook은 오직 page-level 컴포넌트에서 사용할 수 있습니다. fetch와 다르게 asyncData hook은 컴포넌트 인스턴스(this)에 접근할 수 없지만, 인자(argument)로써 context를 받으며 데이터를 호출하기 위해 사용할 있고, Nuxt.js는 자동으로 컴포넌트의 data와 반환된 객체를 병합합니다.
컴포넌트에서 Async data
컴포넌트들은 asyncData 메서드를 가지고 있지 않기때문에 컴포넌트 내에서 server-side 비동기 데이터 호출을 할 수 없습니다. 이러한 제약사항에 관해서 3개의 옵션이 있습니다.
- 버전 2.12+ 또는 최신 버전의 Nuxt에서 new fetch hook 사용하기
mountedhook에서 API 호출 만들고, 로드 되었을때 data property를 설정합니다. 부작용: server side rendering에서 작동하지 않습니다.- page 컴포넌트의
asyncData메서드에서 API 호출 만들고 sub 컴포넌트에 props로 data 전달해줍니다. Server rendering은 잘 작동합니다. 부작용: 페이지의asyncData는 다른 컴포넌트에 대한 data를 불러오기 때문에 덜 합리적일 수도 있습니다.
querystring 변경 감지하기
asyncData 메서드는 기본적으로 querystring의 변경시 호출되지 않습니다. 만약 호출을 원한다면, 예를 들어 pagination 컴포넌트를 개발할때, page 컴포넌트의 watchQuery property에서 감지할 수 있는 매개변수를 설정할 수 있습니다.
(공식 홈페이지 The watchQuery Property 챕터 참조)
요약
지금부터는 공식 홈페이지에서 fetch와 asyncData에 대한 spec에 대해 알아봤으나 난해한 개념을 보충하기 위한 몇 개 사이트의 내용을 요약해보겠습니다.
즉, 아래와 같이 목적을 구분할 수 있다.
asyncData는 컴포넌트가 랜더링 되기전에 컴포넌트 데이터를 구성하는 것에 목적fetch는 컴포넌트가 랜더링 되기전에 비동기 로직을 호출하는 것에 목적
Difference between Asyncdata vs Fetch
출처: https://stackoverflow.com/questions/49251437/difference-between-asyncdata-vs-fetch
asyncData는 컴포넌트 레벨에서 설정 가능하며 Vuex store에서 접근 가능합니다.fetch는 컴포넌트 레벨에서 설정할 수 없으며 Vuex store에서 접근할 수 없습니다.asyncData와fetch둘다 server-side의 초기 렌더링에서 호출됩니다.- 초기 로딩 이후에,
asyncData와fetch는 page의 route가 변경되었을때 호출됩니다.
- 만약 Nuxt 어플리케이션에서,
- Vuex store를 (데이터) 중앙 저장소로 이용하고,
- 어플리케이션 전체에서 Vuex store로 데이터를 접근할 경우
fetch를 사용
- 만약 Nuxt 어플리케이션에서,
- Vuex store를 (데이터) 중앙 저장소로 이용하고,
- 컴포넌트 레벨에서 설정한 옵션을 가지고 있고,
- 특정 route에서 가져온 data가 오직 1개의 컴포넌트에서 사용될 경우,
- Vuex store 또는 컴포넌트 레벨에 대한 권한을 가질수 있는 유연성이 필요한 경우,
asyncData사용
기타 블로그
fetch
- 컴포넌트를 로드하기 전에 호출
- 모든 컴포넌트 에서 사용 가능
Nuxt.js는 컴포넌트가 렌더링되기 전fetchpromise가 종료될 때까지 대기함fetch는 Vuex store의 data를 접근해 사용할때 사용- 첫 번째 인자로
context를 받으며store와params를 사용할 수 있음 - 서버 사이드 렌더링을 위해 서버에서 화면을 구성할 때 컴포넌트가 생성되고 나서 실행됨
- 브라우저에서 URL 주소를 변경해서 페이지를 이동할 때
asyncData
컴포넌트를 로드하기 전에 호출
page 컴포넌트 에서만 사용 가능
asyncData로 생성한 데이터는 data로 생성한 데이터와 머지되어 사용하는 입장에서는 asyncData와 data는 차이가 없다. 단지 초기화시키는 데이터가 동기적으로 실행되는지 비동기적으로 실행되는지에 대한 차이가 있을 뿐이다.첫 번째 인자로
context를 받으며 url의params나query를 사용할 수 있음redirect나 error를 활용하여 원하는 페이지로 리다이렉트 시키거나 에러 페이지를 띄워줄 수 있음
만일 vuex가 설정되었다면, store를 사용 가능
asyncData는 컴포넌트를 초기화 하기 전에 실행되기 때문에 메서드 내부에서는 this를 통해 컴포넌트 인스턴스에 접근할 수 없다.