Nuxt는 Vue.js의 서버사이드 렌더링을 지원하기 위한 프레임워크로써, Vue.js SPA에서 데이터를 호출하는 방식과 다르게 비동기 데이터 호출을 위한 Hook이 따로 존재합니다. 이번 포스트에서는 그 Hook인 fetch
와 asyncData
Hook에 대해 살펴보겠습니다.
fetch & asyncData
일단 공식문서의 간략한 설명을 번역하면 아래와 같다.
fetch
hook (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 에서fetch
hook이 호출되었을때 placeholder를 표시하도록 해줍니다.error
는null
또는 fetch hook이 반환한Error
입니다.timestamp
는 최신 fetch의 timestamp로써,keep-alive
으로 caching 하는 것에 유용합니다.
Nuxt에 의해 fetch가 호출되는 것이외에도 컴포넌트에서 수동으로 this.$fetch()
를 호출해 fetch를 사용할 수도 있습니다.
1 | <template> |
Option
fetchOnServer
:Boolean
orFunction
(기본값: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 사용하기
mounted
hook에서 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
는 컴포넌트가 렌더링되기 전fetch
promise가 종료될 때까지 대기함fetch
는 Vuex store의 data를 접근해 사용할때 사용- 첫 번째 인자로
context
를 받으며store
와params
를 사용할 수 있음 - 서버 사이드 렌더링을 위해 서버에서 화면을 구성할 때 컴포넌트가 생성되고 나서 실행됨
- 브라우저에서 URL 주소를 변경해서 페이지를 이동할 때
asyncData
컴포넌트를 로드하기 전에 호출
page 컴포넌트 에서만 사용 가능
asyncData
로 생성한 데이터는 data로 생성한 데이터와 머지되어 사용하는 입장에서는 asyncData와 data는 차이가 없다. 단지 초기화시키는 데이터가 동기적으로 실행되는지 비동기적으로 실행되는지에 대한 차이가 있을 뿐이다.첫 번째 인자로
context
를 받으며 url의params
나query
를 사용할 수 있음redirect나 error를 활용하여 원하는 페이지로 리다이렉트 시키거나 에러 페이지를 띄워줄 수 있음
만일 vuex가 설정되었다면, store를 사용 가능
asyncData
는 컴포넌트를 초기화 하기 전에 실행되기 때문에 메서드 내부에서는 this를 통해 컴포넌트 인스턴스에 접근할 수 없다.