데이터 fetching - 데이터는 언제 fetch해야할까?

vue-router를 적용하기 전에는 라이프사이클 메서드인 created 메서드 안에서 data를 fetch해왔다.
이제 라우팅을 적용하였으니, navigation이 되기 전에 data를 fetch해올 수 있을 것 같다.
관련한 글이 vue-router 공식문서에 적혀있었다. 내가 좋아하는 공식문서ㅋ-ㅋ
vue-router 공식문서의 Data Fetching을 보고 언제, 어떻게 data fetching을 할 것인지 정리해보고 어떻게 할 것인지를 생각해본다.

정리를 마친 후의 내 생각은, 네비게이션 후에 data를 fetch하는 것이다. 이동 자체가 느린 것은 UX적으로 좋지 않을 것 같다. 이동해서 data를 fetch한 다음에 기본적인 컴포넌트와 skeleton component를 보여주는 것이 더 좋을 것 같다.


컴포넌트를 렌더링하기 전에 data를 fetch하는 시점은 두 지점이 있을 것이다.

  1. 네비게이션 후에 Fetching : 네비게이션을 한 이후에, 컴포넌트의 라이프사이클 훅에서 데이타를 fetch한다. 데이타가 fetch되기 전에는 로딩 상태를 보여준다.

  2. 네비게이션 전에 Fetching : 네비게이션 전에 data를 fetch한다. 데이타가 Fetch된 이후에 네비게이션을 한다.

1. 네비게이션 후 Fetching

컴포넌트로 즉시 navigate하고, 렌더링한다. 그리고 컴포넌트의 created hook에서 데이터를 Fetch한다. 이 방식으로 하면, 데이타가 fetch되는 동안 로딩 상태를 보여줄 수 있다. 그리고 각 상태에 따라 로딩을 다르게 처리할 수 있다.

라우트는 갖고 param이 다를 경우엔 라이프사이클 훅이 호출되지 않는다. 따라서 $route를 watch해서, params가 변경되었을 때 필요한 작업들을 해줘야 한다.

const User = {
  template: '...',
  watch: {
    '$route' (to, from) {
      // 경로 변경에 반응하여...
    }
  }
}
export default {
  data () {
    return {
      loading: false,
      post: null,
      error: null
    }
  },
  created () {
    // fetch the data when the view is created and the data is
    // already being observed
    this.fetchData()
  },
  watch: {
    // 라우트가 변경되는 것을 watch로 확인하여 데이타를 fetch해야한다. -> 라우트는 같고, Params만 변경되면 컴포넌트가 재사용되어 라이프사이클 메서드가 호출되지 않기 때문이다.
    '$route': 'fetchData'
  },
  methods: {
    fetchData () {
      this.error = this.post = null
      this.loading = true
      const fetchedId = this.$route.params.id
      // replace `getPost` with your data fetching util / API wrapper
      getPost(fetchedId, (err, post) => {
        // make sure this request is the last one we did, discard otherwise
        if (this.$route.params.id !== fetchedId) return
        this.loading = false
        if (err) {
          this.error = err.toString()
        } else {
          this.post = post
        }
      })
    }
  }
}

2. 네비게이션 전에 Fetching

새로운 라우트로 네비게이트되기 전에 데이터를 fetch해온다.
이 방법은 들어갈 컴포넌트의 beforeRouteEnter 안에서 데이터를 Fetch하는 것이다.
fetch가 끝나면, next()를 호출한다.
next()는 다음 파이프라인에 있는 훅을 호출할 것이고 호출할 훅이 없으면 navigation이 이루어진다.

만약, 문제가 생기면 next(false)로 네비게이션을 취소할 수 있다.

  • beforeRouteEnter

    • 컴포넌트가 그려지기 전에 호출된다. 컴포넌트가 아직 생성되기 전이므로, this로 컴포넌트 인스턴스에 접근할 수 없다.
    • 이 훅에서 첫 데이터를 fetch해온다.
  • beforeRouteUpdate

    • 이 컴포넌트가 변경되어 렌더링될 때 호출된다.
    • 컴포넌트는 재사용된다. 예를 들어 /foo/1에서 /foo/2로 라우트가 변경되었을 때, Foo 컴포넌트는 그대로 사용하게 된다. 그리고 이 시점에 이 훅이 호출된다.
    • 컴포넌트가 생성된 이후의 시점이므로 this로 컴포넌트 인스턴스에 접근할 수 있다.
    • 이 훅에서 동적으로 라우팅이 변경될 경우, 데이타를 Fetch한다.
export default {
  data () {
    return {
      post: null,
      error: null
    }
  },
  beforeRouteEnter (to, from, next) {
    getPost(to.params.id, (err, post) => {
      next(vm => vm.setData(err, post))
    })
  },
  // when route changes and this component is already rendered,
  // the logic will be slightly different.
  beforeRouteUpdate (to, from, next) {
    this.post = null
    getPost(to.params.id, (err, post) => {
      this.setData(err, post)
      next()
    })
  },
  methods: {
    setData (err, post) {
      if (err) {
        this.error = err.toString()
      } else {
        this.post = post
      }
    }
  }
}

Stale-while-revalidate

SWR이라고 캐쉬된 값 가져오고, 이후에 fetch한 data로 리프레쉬해주는 방식이 있다.
이미 가져온 데이터를 사용함으로써, 유저에게 더 빠른 응답을 줄 수 있다.

vue에서 SWR 개념을 사용할 수 있게 해주는 라이브러리가 swrv이다.

출처

Select a repo