【Nuxt.js】簡単アプリ作ってみた

Nuxt.js勉強会がありました
その復習がてら、簡単なアプリを作ってみました

#今回作成する簡単なアプリケーション内容
・User一覧ページとUser詳細ページだけ
・User一覧の詳細ページへを押すと各Userの詳細ページに遷移
・APIは用意しない、Nuxtの機能を使用してデータレスポンスを参照できるようにする
・デザインは考慮しない
簡単だけどこんな感じ

#Project作成

[node.js](https://nodejs.org/ja/about/)のバージョン確認

 
```console
$ node -v
v10.6.0
```

[npx](https://qiita.com/tonkotsuboy_com/items/8227f5993769c3df533d)がインストールされているか[which](https://webkaru.net/linux/which-command/)コマンドで確認

```
$ which npx
/usr/local/bin/npx
```
では、Project作成をします

今回はnuxtAppというディレクトリを作成し、移動した後にnuxtApp内にプロジェクトを作成してる

```
$ mkdir nuxtApp
$ cd nuxtapp
$ npx create-nuxt-app 
```
上記の作成コマンドを実行するといつくか質問をされるので以下のように選択

```
> Generating Nuxt.js project in /Users/Username/nuxtApp
? Project name (nuxtApp)
```
プロジェクト名を何にするか聞かれますがそのままでいいのでEnter

```
? Project description (My epic Nuxt.js project)
```
ここもEnter

```
? Use a custom server framework (Use arrow keys)
❯ none
  express
  koa
  adonis
  hapi
  feathers
  micro
```
サーバーサイドのフレームワークを聞かれる
ここはnoneを選択

```
? Use a custom UI framework (Use arrow keys)
  none
  bootstrap
  vuetify
  bulma
  tailwind
❯ element-ui
  buefy
```
好きな UI フレームワークを選択
最近は[element-ui](https://element.eleme.io/#/en-US)を使ってるのでelement-uiを選択

```
? Choose rendering mode (Use arrow keys)
❯ Universal
  Single Page App
```
Nuxtのモードを選択
> UniversalとSingle Page Appの違い
UniversalはUIレンダリング全体を担うフレームワークとして使うことができます
このサーバーは[ホットリローディング](https://vue-loader-v14.vuejs.org/ja/features/hot-reload.html)及び、[VueServerRenderer](https://ssr.vuejs.org/ja/)を備えており、アプリケーションが自動的に[サーバーサイドレンダリング](https://ssr.vuejs.org/ja/#%E3%82%B5%E3%83%BC%E3%83%90%E3%82%B5%E3%82%A4%E3%83%89%E3%83%AC%E3%83%B3%E3%83%80%E3%83%AA%E3%83%B3%E3%82%B0-ssr-%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B)するよう設定されています
一方、Single Page Appは何かしらの理由でサーバーサイドレンダリングを使いたくない、またはアプリケーションを静的にホスティングする必要があるときはこちらを使用します

```
? Use axios module (Use arrow keys)
  no
❯ yes
```
HTTPクライアントとしてNuxt公式の[Axios module](https://www.yoheim.net/blog.php?q=20170801)を使用するか聞かれます
今回は使用するのでyesを選択

```
? Use eslint (Use arrow keys)
❯ no
  yes
```
[ESLint](https://qiita.com/mysticatea/items/f523dab04a25f617c87d)はnoを選択

```
? Use prettier (Use arrow keys)
❯ no
  yes
```
[Prettier](https://ics.media/entry/17030)も使わないのでnoを選択

```
? Author name (Username)
```
ここもEnter

```
? Choose a package manager (Use arrow keys)
❯ npm
  yarn
```
パッケージマネージャーとしてnpmもしくはyarnのどちらを使用するか聞かれます
今回はnpmを選択

これでプロジェクト作成ができた！

#Server起動

プロジェクトが作成できたので、Serverを起動して確認してみよう

```
$ cd nuxtApp
$ npm run dev
```

※ ServerはControl + Cで停止できます

起動ができたら[localhost:3000](http://localhost:3000/)で確認してみよう

#User一覧ページ作成

ユーザーを一覧表示させるページを作成していきます

まずは、pagesディレクトリ直下にusersディレクトリを作成
そしてusersディレクトリにindex.vueを作成

```vue:pages/users/index.vue
<template>
  <div>
    <h1>User一覧ページ</h1>
  </div>
</template>

<script>
</script>
```

作成したら[localhost:3000/users/](http://localhost:3000/users)で確認してみよう
User一覧ページと表示されていればOK

Nuxt.jsではpages/にディレクトリを作成するとそれがルートになります
ここらへんはNuxtがよしなにやってくれてます笑

#Userー詳細ページ作成

User一覧ページができたので、次にユーザー詳細ページを作ります
pages/usersディレクトリに_id.vueを作ります

_id.vueをusersディレクトリに作成することで、
自動的に/users/:idというルートが作成されます

```vue:pages/users/_id.vue
<template>
  <div>
    <h1>User詳細ページ</h1>
  </div>
</template>

<script>
</script>
```

作成できたら[localhost:3000/users/1](http://localhost:3000/users/1)にアクセスして確認してみよう
ユーザー詳細ページと表示されていればOK

#レスポンスデータを参照できる仕組みをつくる
　
今回はAPIを使わずにレスポンスデータを参照できる仕組みを作っていきます

では、staticディレクトリにapiディレクトリを作成し、その中にusers.jsonというファイルを作成
ファイルを作成することで、自動的に/api/users.jsonから参照できるようになります

```json:static/api/users.json
[
  {
    "id"        : 1,
    "username"  : "tarou",
    "password"  : "password1"
  },
  {
    "id"        : 2,
    "username"  : "hanako",
    "password"  : "password2"
  }
]
```

作成できたら[localhost:3000/api/users.json](http://localhost:3000/api/users.json)で確認してみよう
jsonデータが確認できればOK

次に同じような感じでstatic/api/detail_users.jsonを作成

```json:static/api/detail_users.json
[
  {
    "detail_id" : 1,
    "height" : 170,
    "weight" : 60,
    "sex"    : "男"
  },
  {
    "detail_id" : 2,
    "height" : 156,
    "weight" : 43,
    "sex"    : "女"
  }
]
```

これも[localhost:3000/api/detail_users.json](http://localhost:3000/api/detail_users.json)で確認しよう

#Axiosの設定

Axiosの設定をします
pluginsディクレトリにaxios.jsを作成

```js:plugins/axios.js
export default function ({ $axios, redirect }) {
  $axios.onRequest(config => {
    if (process.env.NODE_ENV === 'development') {
      config.method = 'get'
      config.baseURL = 'http://localhost:3000/api',
      config.url += '.json'
    }
    return config
  })
}
```

<b>axios設定について</b>
axiosでusers.jsonのデータが欲しい際に、`http://localhost:3000/api/users.json`にGETリクエストを送ると思いますが、設定することにより`users`にGETリクエストを送るだけでデータを取得できるようになります

```js:例
//users.jsonを受け取る処理
$axios.$get('http://localhost:3000/api/users.json') // これが...
// ⇩
$axios.$get('users') // こうかけるようになる！　便利！
```

作成できたら、次にaxios.jsが読み込まれるようにnuxt.config.jsの編集

```js:nuxt.config.js
...


/*
** Plugins to load before mounting the App
*/
plugins: [
  '@/plugins/element-ui',
  '@/plugins/axios' // <-追加
],


...
```

編集が完了したら一度Control + CでServerを停止させます
そしてnpm run-script buildを実行します

```
$ npm run-script build
```

そうすることでaxiosの設定が読み込まれるようになります
buildが完了したらもう一度Serverを起動

```
$ npm run dev
```

これでaxiosの設定が終わりました！

# User一覧ページにUser一覧を表示させる

axiosを使用して、user.jsonに記述してあるデータを一覧表示させたいと思います
ついでに各User詳細ページへのリンクも作成

ではでは、pages/users/index.vueを編集

```vue:pages/users/index.vue
<template>
  <div>
    <h1>User一覧ページ</h1>
    <div v-for="user in users" :key="user.id">
      <p>ID: {{ user.id }}</p>
      <p>username : {{ user.username }}</p>
      <p>password : {{ user.password }}</p>
      <p><nuxt-link :to="`/users/${user.id}`">User詳細ページへ</nuxt-link></p>
    </div>
  </div>
</template>

<script>
export default {
  async asyncData ({ app }) {
    const users = await app.$axios.$get('users')
    return {
      users
    }
  }
}
</script>
```

ここではaxiosで取得したUser情報をv-forで回して表示させています
各User詳細ページへのリンクはURLにuser.user_id変数をクエリパラメータとして渡す実装をしてます

[localhost:3000/users](http://localhost:3000/users)を確認してみましょう！
user情報が表示されていると思います
さらに、ユーザー１人目のユーザー詳細ページをクリックすると、上手くusers/1に飛ぶと思います

#User詳細ページにUser詳細を表示させる

次はuser詳細ページです
users/idのidの部分に当たる各Userの情報をaxiosで取得して表示する処理を書きます
pages/users/_id.vueを編集しましょう

```vue:pages/users/_id.vue
<template>
  <div>
    <h1>User詳細ページ</h1>
    <div v-if="userId, detailUserFilter">
      <p>ユーザID :{{ userId }}</p><br>
      <p>体重 : {{ detailUserFilter.weight }}</p>
      <p>身長 : {{ detailUserFilter.height }}</p>
      <p>性別 : {{ detailUserFilter.sex }}</p>
      <nuxt-link :to="`/users`">User一覧ページへ</nuxt-link>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      detailUsers: [{}]
    }
  },
  computed: {
    userId: function() {
      return this.$route.params.id
    },
    detailUserFilter: function() {
      let detailUsers = this.detailUsers[this.userId - 1]
      return detailUsers
    }
  },
  async beforeCreate() {
    this.detailUsers = await this.$axios.$get("detail_users")
  }
}
</script>
```

ここでは、axiosでdetail_usersの情報を全部取得して、dataのdetailUsersに格納してます

```vue:beforeCreate
<script>
...
async beforeCreate() {
  this.detailUsers = await this.$axios.$get("detail_users")
}
...
</script>
```

computed内ではuserIdを返すuserIdメソッド、
渡ってきたクエリパラメータから紐づくdetailUsers情報を返すdetailUserFilterメソッド、
を定義してある

```vue:computed
<script>
...
data() {
    return {
      detailUsers: [{}]
    }
  },
computed: {
  userId: function() {
    // クエリパラメータを取得してreturn
    return this.$route.params.id
  },
  detailUserFilter: function() {
    // dataのdetailUsersからクエリパラメータで取得したuserIdに紐づく配列をreturn
    let detailUsers = this.detailUsers[this.userId - 1]
    return detailUsers
  }
},
...
</script>
```

作成できたら[localhost:3000/users](http://localhost:3000/users)でUser一覧ページから各User詳細ページのリンクをクリックしてみましょう！

これでUser詳細ページができました！　これで完成です