macotok / nuxt-tutorial

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Nuxt.js Tutorial

特徴

  • Vue.jsでSSRを行うためのフレームワーク
  • SSRした結果を静的ファイルとして書き出すこともできる
  • webpackの設定がすでにされている
  • Vue Routerの設定なしでルーティング設定ができる

※SSR HTMLを構築する仕組みがサーバー側にもクライアント側にも備わっていること

プロジェクトの作成

$ npx create-nuxt-app sample-app

開発用ローカルサーバーの起動

$ npm run dev

VueCLIとどちらを使う?

下記、実装する場合はNuxt.jsを使った方が楽

  • ルーティングが必要
  • SSRが必要
  • 認証が必要

ディレクトリについて

Nuxt.jsをinstallすると下記ディレクトリ/ファイルが作られる

├── nuxt.config.js
├── assets
├── static
├── components
├── layouts
├── pages
├── middleware
├── plugins
└── store

nuxt.config.js

  • Nuxt.jsアプリケーションの設定ファイル
  • plugins/middlewareなどの設定、webpackの拡張

assets

  • コンパイルされていないsassファイルやjsファイルを管理
  • vue-loaderによってコンパイルなどの処理が行われる

static

  • webpackを通す必要のないimgファイルなどの静的なファイルを管理
  • staticディレクトリにimage.pngを置いた場合、アプリケーション内では/image.pngで参照

components

  • Vue.jsのコンポーネントを管理

layouts

  • 共通のレイアウト、個別のレイアウトなどを管理
  • ページコンポーネントからレイアウトを指定
  • create-nuxt-appで作成するとデフォルトのレイアウトコンポーネントとして、/layouts/default.vueが作られる
  • 共通のレイアウトはdefault.vue、個別のレイアウトは新たに作成
  • <nuxt />はVue Routerの<router-view>にあたるもので、ルーティングにマッチしたページコンポーネントがレンダリングされる。そのためレイアウトコンポーネントには<nuxt />を書く

個別レイアウトの/layouts/top.vueを読み込む場合

export default {
  layout: 'top',
}

pages

pagesディレクトリの中の構造がそのままルーティングになる。

  • pagesディレクトリ直下のindex.vueが/
  • pages/users/index.vueが/users
  • _user.vueのようにファイル名の先頭に_をつけると動的なルーティング

store

  • vuexのファイルを管理
  • index.jsを生成すると自動的にVuexストアを有効にする

asyncDataとfetchの機能

Vue.jsとNuxt.jsでAPI取得方法が違う

  • Nuxt.jsを使わない場合、Vueインスタンスの初期化時やコンポーネントのcreatedのフックなどでAPIを叩いて、Vuexのストアやコンポーネントのdataに格納
  • Nuxt.jsの場合は、ページコンポーネントが読み込まれる前に呼び出されるasyncDatafetchというメソッドでページに必要なデータを読み込む
  • asyncDatafetchはどちらもデータを取得するためのメソッド
  • asyncDataはコンポーネントのdataに非同期でデータをセットするときに使う
  • fetchはVuexストアにcommitdispatchするときに使う

asyncData

  • asyncDataメソッド内でreturnしたものが、コンポーネントのdataとマージされて<template>などで使える
  • ルートのVueインスタンスへの参照がappとして渡されるので、app.$axiosでaxiosを参照
  • Vue DevToolsでコンポーネントのdataにAPIのレスポンスが確認できる
  • asyncDataとfetchはVueインスタンスが作成される前に実行されるメソッドなのでthisが存在しない
  • Vueインスタンスへの参照はcontextオブジェクトに格納されている(app.$axiosの箇所)
  • asyncDataとfetchはともにSSR対応
<template>
  <div>
    <div>
      <img :src="avatar_url" width="100">
      <span>
        {{name}}
      </span>
    </div>
    <a :href="html_url">
      {{html_url}}
    </a>
  </div>
</template>

<script>
  export default {
    name: 'user',
    async asyncData({ app, params }) {
      const data = await app.$axios.$get(`https://api.github.com/users/${params.user}`)
      return data;
    }
  }
</script>

SSRについて

  • SSRはブラウザで最初にアクセスしたページのコンテンツをすばやくレンダリングするためのもの
  • Vue Routerによって遷移した場合はクライアントサイドでレンダリングされる
<a href="/hoge">サーバーサイドでレンダリング</a>
<nuxt-link to="/hoge">クライアントサイドでレンダリング</nuxt-link>

Vuexストアを使う

  • Nuxt.jsはVuexをnpmからinstallしなくても利用できる
  • Vuexストアを追加する方法はクラシックモードとモジュールモードの2つある
  • Vuexストア内に定義するstateは必ずfunctionにする。SSRのときに意図しないstateの共有が起こらないようにするため

クラシックモード

  • store/index.jsnew Vuex.Store()を返すメソッドをexportすると有効になる
  • ストアインスタンスを返すというルール以外は、通常Vuexを使う場合と同じ使い方
import Vuex from 'vuex';

export default () => {
  return new Vuex.Store({
    state() {
      return {
        counter: 0,
      }
    }
  })
}

モジュールモード

  • storeディレクトリ内のファイル構造によってnamespacedなモジュールを持ったストアを自動で構築する
  • store/index.jsstatemutationsなどをexportすることで有効になる
  • モジュールはstoreディレクトリにあるindex.js以外のファイルまたはディレクトリが自動的にモジュールして追加される
  • 画面が複数ある場合はモジュールモードを使う
export const state = () => ({
  counter: 0
})
export const state = () => ({
  items: []
})

この2つのファイルからVuexストアが構築される

new Vuex.Store({
  state: () => ({
    counter: 0
  }),
  modules: {
    namespaced: true,
    todos: {
      state: () => ({
        items: []
      })
    }
  }
});

Vuexストアからstateを読み込む

  • store/index.jsstate userを設定
  • setUserはページコンポーネントから取得
  • mapStatestate userを取得。templateで展開
  • fetchメソッドはstoreのデータをページコンポーネントのレンダリングより前に取得するメソッド
  • fetchメソッドでPromiseを返す
  • store.commitstoreにデータを格納
  • データ取得の処理をVuexストアで行う場合はstore.dispatchreturnする

store/index.js

export const state = () => ({
  user: null,
});

export const mutations = {
  setUser(state, user) {
    state.user = user
  }
}

pages/_user.vue

<template>
  <div>
    <div>
      <img :src="user.avatar_url" width="100">
      <span>
        {{user.name}}
      </span>
    </div>
    <a :href="user.html_url">
      {{user.html_url}}
    </a>
  </div>
</template>

<script>
  import { mapState } from 'vuex';
  export default {
    name: 'user',
    async fetch({ app, params, store }) {
      const user = await app.$axios.$get(
        `https://api.github.com/users/${params.user}`
      )
      store.commit('setUser', user);
    },
    computed: {
      ...mapState({
        user: 'user',
      })
    }
  }
</script>

dispatchを使う場合

fetch({ app, params, store}) {
  return store.dispatch('fetchUser', params)
}

参考サイト

About


Languages

Language:Vue 70.4%Language:JavaScript 29.6%