[Nuxt.js] ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ํ˜ธ์ถœ ๋ฐฉ๋ฒ•

2022. 5. 22. 02:17ใ†Front-End ์ž‘์—…์‹ค/Nuxt.js

728x90
๋ฐ˜์‘ํ˜•

 

 

 

๐Ÿš€ Nuxt.js ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ

    ๐Ÿ”ฝ  ํ˜ธ์ถœ ๋ฐฉ๋ฒ•

        ๐Ÿ“ฆ ๊ฐœ์š”

Nuxt.js๋Š” SSR(Server Side Rendering) Framework๋กœ Vue.js Single Paga Application๊ณผ `REST API` ํ˜ธ์ถœ ๋ฐฉ์‹์„ ๋‹ค๋ฅด๊ฒŒ ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

        ๐Ÿ“ฆ Single Page Application๊ณผ์˜ ์ฐจ์ด์ 

CSR(Client Side Rendering)์ธ Vue Single Page Application Data ํ˜ธ์ถœ ๋ฐฉ์‹์€ ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<!-- UserProfile.vue -->
<template>
  <div>
    <p>{{ user }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: {},
    }
  },
  methods: {
    async fetchUser() {
      const response = await axios.get('/users/1');
      this.user = response.data;
    }
  },
  created() {
    this.fetchUser();
  },
}
</script>

 

`Created()` Life Cycle Hook์„ ์ด์šฉํ•ด Component๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด Server์— Data๋ฅผ ์š”์ฒญํ•ด ๋ฐ›์•„์˜จ ๊ฒฐ๊ณผ๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•˜๋Š” Code์—์š”. ์ด๋•Œ Server์— Data๋ฅผ ์š”์ฒญํ•˜๋Š” ์‹œ์ ์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ Vue.js Code๊ฐ€ ํ™”๋ฉด์˜ `DOM`์„ ๊ตฌ์„ฑํ•˜๊ณ , Script๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์‹œ์ ์ธ ๊ฒƒ์ด์—์š”. `Client Side Rendering๊ณผ ServerSide Rendering ์ฐจ์ด์ `์˜ ์•„๋ž˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด

์ถœ์ฒ˜ :&nbsp;https://joshua1988.github.io/vue-camp/nuxt/ssr.html#%E1%84%8F%E1%85%B3%E1%86%AF%E1%84%85%E1%85%A1%E1%84%8B%E1%85%B5%E1%84%8B%E1%85%A5%E1%86%AB%E1%84%90%E1%85%B3-%E1%84%89%E1%85%A1%E1%84%8B%E1%85%B5%E1%84%83%E1%85%B3-%E1%84%85%E1%85%A6%E1%86%AB%E1%84%83%E1%85%A5%E1%84%85%E1%85%B5%E1%86%BC



Client Side Rendering์€ ๋นˆ ํ™”๋ฉด์„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ฐ›์•„ ํ™”๋ฉด์— ๋ฟŒ๋ฆด ์š”์†Œ์™€ Data๋ฅผ ๋ชจ๋‘ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ตฌ์„ฑํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์œ„์™€ ๊ฐ™์€ code๊ฐ€ ๊ฐ€๋Šฅํ•ด์š”.

ํ•˜์ง€๋งŒ Nuxt.js๋Š” Server์—์„œ Page ๋‚ด์šฉ์„ ๋ชจ๋‘ ๊ทธ๋ ค ๋ธŒ๋ผ์šฐ์ €๋กœ ๊ฐ€์ ธ๊ฐ€์•ผ ํ•˜๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

 

 

        ๐Ÿ“ฆ REST API ํ˜ธ์ถœ ๋ฐฉ์‹

์•ž์—์„œ ๋ณธ ๊ฒƒ์ฒ˜๋Ÿผ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ํŽ˜์ด์ง€์— ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด `Vue Lift Cycle Hook`์„ ์ด์šฉ ํ•œ ๊ฒƒ์ด์—์š”. Nuxt.js์—์„œ๋Š” ์•„๋ž˜ 2๊ฐ€์ง€ ์ธ์Šคํ„ด์Šค ์˜ต์…˜ ์†์„ฑ์ด ๋ณ„๋„ ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

โ— acnycData
`acyncData`๋Š” Page Component(pages Package ์•„๋ž˜ ์œ„์น˜ํ•˜๋Š” Component)์—๋งŒ ์ œ๊ณต๋˜๋Š” ์†์„ฑ ์ž…๋‹ˆ๋‹ค. `asyncData`๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด Server์—๊ฒŒ Data๋ฅผ ์š”์ฒญํ•  ์ˆ˜ ์žˆ์–ด์š”.

 

์˜ˆ์‹œ ์ฝ”๋“œ

<!-- pages/user.vue -->
<template>
  <div>
    <p>{{ user }}</p>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  // params์˜ id๊ฐ€ 1์ด๋ผ๊ณ  ๊ฐ€์ •
  async asyncData({ params, $http }) {
    const response = await axios.get(`/users/${params.id}`);
    const user = response.data;
    return { user }
  }
}
</script>
๋ฐ˜์‘ํ˜•

 

์œ„ codesms URL `/user`๋กœ ์ ‘๊ทผํ•  ๋•Œ `user.vue` Component๋ฅผ ํ™”๋ฉด์— ๊ทธ๋ฆฌ๊ธฐ ์ „์— Data๋ฅผ ์š”์ฒญํ•˜๋Š” Code์—์š”.
Data๋ฅผ ๋‹ค ๋ฐ›์•„์™€์•ผ์ง€๋งŒ Data๋ฅผ ๋“ค๊ณ  `<template></template>` ์˜์—ญ์˜ Code๋ฅผ ํ™”๋ฉด์— ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์น˜ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ทฐ ๋ผ์šฐํ„ฐ์—์„œ ๋„ค๋น„๊ฒŒ์ด์…˜ ๊ฐ€๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ๋ฐ›์•„์™”์„ ๋•Œ ํŽ˜์ด์ง€๋ฅผ ์ง„์ž…ํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.


  - asyncData Parameter
`asyncData` ์†์„ฑ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” `context` ์†์„ฑ์ธ ๊ฒƒ์ด์—์š”. Context ์†์„ฑ์€ Nuxt.js ์ „๋ฐ˜์— ๊ฑธ์ณ ๊ณต์šฉ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์†์„ฑ์œผ๋กœ Plug In, Middleware ์†์„ฑ์—์„œ๋„ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. Context์—๋Š” Store, Roeuter ๊ด€๋ จ ์ •๋ณด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, SSR์—์„œ ์š”์ฒญ, ์‘๋‹ต ๊ด€๋ จ ์†์„ฑ๋„ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์š”.

 

์˜ˆ์‹œ ์ฝ”๋“œ

function (context) { // asyncData, plugins, middleware, ...
  // Always available
  const {
    app,
    store,
    route,
    params,
    query,
    env,
    isDev,
    isHMR,
    redirect,
    error,
   $config
  } = context

  // Only available on the Server-side
  if (process.server) {
    const { req, res, beforeNuxtRender } = context
  }

  // Only available on the Client-side
  if (process.client) {
    const { from, nuxtState } = context
  }
}

 

 

  - asyncData Error Code

`acyncData` ์†์„ฑ์—์„œ API ํ˜ธ์ถœ Error๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด Error Page๋กœ ์ด๋™์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์–ด์š”.

export default {
  async asyncData({ params, $http, error }) {
    try {
      const response = await axios.get(`/users/${params.id}`);
      const user = response.data;
      return { user }
    } catch(e) {
      error({ statusCode: 503, message: 'API ์š”์ฒญ์ด ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค ๋‹ค์‹œ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”' })
    }
  }
}

 




โ— fetch
`fetch`๋Š” Page Component ๋ถ„ ์•„๋‹ˆ๋ผ ์ผ๋ฐ˜ Vue Component์—์„œ๋„ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” Data ํ˜ธ์ถœ ์†์„ฑ์ธ ๊ฒƒ์ด์—์š”. ๋‹ค์Œ 2๊ฐ€์ง€ ์ƒํ™ฉ์—์„œ ํ˜ธ์ถœ์ด ๋œ๋‹ต๋‹ˆ๋‹ค.

   โ—ฆ SSR(Server Side Rendering)์„ ์œ„ํ•ด Server์—์„œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ๋•Œ Component๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ๋‚˜์„œ ์‹คํ–‰. 
   โ—ฆ ๋ธŒ๋ผ์šฐ์ €์—์„œ URL ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•ด์„œ Page ์ด๋™ํ•  ๋•Œ.


์˜ˆ์‹œ ์ฝ”๋“œ

<!-- components/UserProfile.vue -->
<template>
  <div>{{ user }}</div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: {},
    }
  },
  async fetch() {
    const res = await axios.get('https://jsonplaceholder.typicode.com/users/1');
    this.user = res.data;
  },
}
</script>

 

๋งŒ์•ฝ ์œ„ Component๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด main.vue Component์— ๋“ฑ๋ก ๋˜์–ด ์žˆ๊ณ , URL ์ฃผ์†Œ๊ฐ€ `/` ์—์„œ `/main`์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด Component๊ฐ€ ํ™”๋ฉด์— ๋ถ€์ฐฉ๋˜๊ณ  ๋‚˜์„œ(mounted) `fetch`์•ˆ์— Data Call Logic์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

<!-- pages/main.vue -->
<template>
  <div>
    <h1>๋ฉ”์ธ ํŽ˜์ด์ง€</h1>
    <UserProfile></UserProfile>
  </div>
</template>

<script>
import UserProfile from '@/components/UserProfile.vue'

export default {
  components: {
    UserProfile,
  },
}
</script>

 

์ถœ์ฒ˜ :&nbsp;https://joshua1988.github.io/vue-camp/nuxt/data-fetching.html#fetch

 

์œ„ ๋™์ž‘์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ ์ตœ์ดˆ `/`๋กœ ์ ‘๊ทผํ•˜๊ณ , `/main`์œผ๋กœ ์ด๋™์„ ํ–ˆ๊ธฐ์— Component๊ฐ€ ํ™”๋ฉด์— ๋จผ์ € ๋ฟŒ๋ ค์ง€๊ณ  ๋‚˜์„œ fetch ํ˜ธ์ถœ์ด ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์— `/main`์œผ๋กœ ์ด๋™ํ•˜๊ณ  ๋‚˜๋ฉด Data๋ฅผ ๋ฐ›์•„์˜ค๋Š” ๋™์•ˆ `user` ์†์„ฑ์˜ ๊ธฐ๋ณธ ๊ฐ’์ธ `{}`๊ฐ€ ๋จผ์ € ํ™”๋ฉด์— ๋ณด์ด๊ณ  ์ž ์‹œ ๋’ค ๋ฐ›์•„์˜จ Data๊ฐ€ ํ™”๋ฉด์— ๋ฟŒ๋ ค์ง€๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์š”.

์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ ์ตœ์ดˆ Web Service๋ฅผ `/main`์œผ๋กœ ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด Server ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ๋•Œ ํ˜ธ์ถœ ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ™”๋ฉด์— Data๊ฐ€ ํ˜ธ์ถœ๋œ ์ƒํƒœ๋กœ Page๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋  ๊ฒƒ์ด์—์š”.

์ถœ์ฒ˜ :&nbsp;https://joshua1988.github.io/vue-camp/nuxt/data-fetching.html#fetch

 

  - fetch ํŠน์ง•

fetch๋Š” asyncData์™€ ๋‹ค๋ฅด๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์€ ์†์„ฑ๋“ค์ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค.

 

   โ—ฆ $fetchState : Data ํ˜ธ์ถœ ์ƒํƒœ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ์†์„ฑ์œผ๋กœ ์ธ์Šคํ„ด์Šค๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ ํ˜ธ์ถœ ์ƒํƒœ์— ๋”ฐ๋ผ `pending`, `error`, `timestamp` ์ œ๊ณต.

   โ—ฆ $fetch : fetch Logic์„ ๋‹ค์‹œ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ํ•จ์ˆ˜.

   โ—ฆ fetchOnServer : SSR์‹œ์— Server์—์„œ `fetch`๋ฅผ ์‹คํ–‰ํ• ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•˜๋Š” ์†์„ฑ์œผ๋กœ ๊ธฐ๋ณธ๊ฐ’์€ `true`.

 

 

์˜ˆ์‹œ ์ฝ”๋“œ

<template>
  <div>
    <article>
      <p v-if="$fetchState.pending">์‚ฌ์šฉ์ž API ํ˜ธ์ถœ ์ค‘</p>
      <p v-else-if="$fetchState.error">์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค</p>
      <div v-else>{{ user }}</div>
    </article>
    <button @click="fetchUser">๋‹ค์‹œ ํ˜ธ์ถœํ•˜๊ธฐ</button>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      user: {},
    }
  },
  methods: {
    fetchUser() {
      // fetch ์†์„ฑ์˜ ๋กœ์ง์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
      this.$fetch();
    }
  },
  async fetch() {
    const res = await axios.get('https://jsonplaceholder.typicode.com/users/1');
    this.user = res.data;
  },
  // ์•„๋ž˜ ์†์„ฑ์„ 'false'๋กœ ๋ฐ”๊พธ๋ฉด ์„œ๋ฒ„์—์„œ ํ™”๋ฉด์„ ๊ตฌ์„ฑํ•  ๋•Œ `fetch` ์†์„ฑ์˜ ๋กœ์ง์ด ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  fetchOnServer: false
}
</script>

 

 

 

 

 

 

 

728x90
๋ฐ˜์‘ํ˜•