Skip to content

데이터 가져오기

라우트가 활성화될 때 서버에서 데이터를 가져와야 하는 경우가 있습니다. 예를 들어 유저 프로필을 렌더링하기 전에 서버에서 유저 데이터를 가져와야 합니다. 이를 달성하는 방법에는 두 가지가 있습니다:

  • 탐색 후 데이터 가져오기: 먼저 탐색을 수행한 다음, 새로 사용되는 컴포넌트의 생명주기 훅에서 데이터를 가져옵니다. 데이터를 가져오는 동안 로딩 상태를 표시합니다.

  • 탐색 전 데이터 가져오기: 탐색 전에 라우트 엔터 가드에서 데이터를 가져오고, 데이터를 가져온 후에 탐색을 수행합니다.

기술적으로 두 방법 모두 유효하며, 궁극적으로는 목표로 하는 사용자 경험(UX)에 따라 달라집니다.

탐색 후 가져오기

이 접근 방식은 즉시 탐색하고 새로 사용되는 컴포넌트를 렌더링하면, 컴포넌트 자체에서 데이터를 가져옵니다. 네트워크를 통해 데이터를 가져오는 동안 로딩 상태를 표시할 필요가 있으며, 각 뷰마다 로딩을 다르게 처리할 수도 있습니다.

route.params.id를 기반으로 게시물 데이터를 가져와야 하는 Post 컴포넌트가 있다고 가정해봅시다:

vue
<template>
  <div class="post">
    <div v-if="loading" class="loading">Loading...</div>

    <div v-if="error" class="error">{{ error }}</div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>

<script setup>
import { ref, watch } from 'vue'
import { useRoute } from 'vue-router'
import { getPost } from './api.js'

const route = useRoute()

const loading = ref(false)
const post = ref(null)
const error = ref(null)

// 라우트의 파라미터를 감시하여 데이터를 다시 가져옵니다.
watch(() => route.params.id, fetchData, { immediate: true })

async function fetchData(id) {
  error.value = post.value = null
  loading.value = true
  
  try {
    // `getPost`를 데이터를 가져오는 유틸리티나 API 래퍼로 변경하세요.
    post.value = await getPost(id)  
  } catch (err) {
    error.value = err.toString()
  } finally {
    loading.value = false
  }
}
</script>
vue
<template>
  <div class="post">
    <div v-if="loading" class="loading">Loading...</div>

    <div v-if="error" class="error">{{ error }}</div>

    <div v-if="post" class="content">
      <h2>{{ post.title }}</h2>
      <p>{{ post.body }}</p>
    </div>
  </div>
</template>

<script>
import { getPost } from './api.js'

export default {
  data() {
    return {
      loading: false,
      post: null,
      error: null,
    }
  },
  created() {
    // 라우트의 파라미터를 감시하여 데이터를 다시 가져옵니다.
    this.$watch(
      () => this.$route.params.id,
      this.fetchData,
      // fetch the data when the view is created and the data is
      // already being observed
      { immediate: true }
    )
  },
  methods: {
    async fetchData(id) {
      this.error = this.post = null
      this.loading = true

      try {
        // `getPost`를 데이터를 가져오는 유틸리티나 API 래퍼로 변경하세요.
        this.post = await getPost(id)
      } catch (err) {
        this.error = err.toString()
      } finally {
        this.loading = false
      }
    },
  },
}
</script>

탐색 전 가져오기

이 접근 방식은 새로운 라우트로 탐색하기 전에 데이터를 가져옵니다. 새로 사용되는 컴포넌트의 beforeRouteEnter 가드에서 데이터 가져오기를 수행하고, 가져오기가 완료된 후에만 next를 호출할 수 있습니다. next에 전달된 콜백은 컴포넌트가 마운트된 후 호출됩니다:

js
export default {
  data() {
    return {
      post: null,
      error: null,
    }
  },
  async beforeRouteEnter(to, from, next) {
    try {
      const post = await getPost(to.params.id)
      // `setPost`는 아래에 정의된 메서드입니다.
      next(vm => vm.setPost(post))
    } catch (err) {
      // `setError`는 아래에 정의된 메서드입니다.
      next(vm => vm.setError(err))
    }
  },
  // 이 컴포넌트가 이미 렌더링 되어있고 라우트가 변경되는 경우,
  // 로직이 약간 다릅니다.
  beforeRouteUpdate(to, from) {
    this.post = null
    getPost(to.params.id).then(this.setPost).catch(this.setError)
  },
  methods: {
    setPost(post) {
      this.post = post
    },
    setError(err) {
      this.error = err.toString()
    }
  }
}

유저는 새로 사용되는 뷰의 리소스를 가져오는 동안 이전 뷰에 머물게 됩니다. 따라서 데이터를 가져오는 동안 로딩 상태를 표시하는 것이 좋습니다. 데이터 가져오기가 실패한 경우, 전역 경고 메시지를 표시하는 것도 필요합니다.

Released under the MIT License.