Skip to content

데이터 가져오기

때로는 라우트가 활성화될 때 서버에서 데이터를 가져와야 합니다. 예를 들어 사용자 프로필을 렌더링하기 전에 서버에서 사용자 데이터를 가져와야 할 수 있습니다. 이를 구현하는 방법은 크게 두 가지입니다:

  • 내비게이션 후 가져오기: 먼저 내비게이션을 수행하고, 들어오는 컴포넌트의 라이프사이클 훅에서 데이터를 가져옵니다. 데이터를 가져오는 동안 로딩 상태를 표시합니다.

  • 내비게이션 전 가져오기: 라우트 진입 가드에서 내비게이션 전에 데이터를 가져오고, 데이터 가져오기가 끝난 뒤에 내비게이션을 수행합니다.

기술적으로는 둘 다 유효한 선택이며, 결국 어떤 사용자 경험을 목표로 하는지에 따라 달라집니다.

내비게이션 후 가져오기

이 접근 방식을 사용하면 내비게이션을 수행하고 들어오는 컴포넌트를 즉시 렌더링한 뒤, 컴포넌트 자체에서 데이터를 가져옵니다. 이렇게 하면 네트워크를 통해 데이터를 가져오는 동안 로딩 상태를 표시할 수 있고, 각 뷰마다 로딩을 다르게 처리할 수도 있습니다.

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)

// 데이터를 다시 가져오기 위해 라우트의 params를 watch합니다
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() {
    // 데이터를 다시 가져오기 위해 라우트의 params를 watch합니다
    this.$watch(
      () => this.$route.params.id,
      this.fetchData,
      // 뷰가 생성될 때 데이터를 가져오며, 데이터는
      // 이미 관찰되고 있습니다
      { 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()
    },
  },
}

들어오는 뷰에 필요한 리소스를 가져오는 동안 사용자는 이전 뷰에 머무르게 됩니다. 따라서 데이터를 가져오는 동안 진행 표시줄이나 어떤 형태의 표시기를 보여 주는 것이 좋습니다. 데이터 가져오기에 실패하면 전역 경고 메시지 같은 것도 표시해야 합니다.

모두를 위한 문서 한글화