Nuxt.jsのasyncData メソッドを使ってRSSを読み込む

この記事は[オールアバウトアドベントカレンダー](https://qiita.com/advent-calendar/2017/allabout)18日目の記事です

Nuxt.jsの機能を使って
RSSを取得して値を書き出してみます

# 使う機能
**asyncData メソッド**
> サーバーサイドでデータを取得し、それをレンダリングしたいことがあるでしょう。Nuxt.js はコンポーネントのデータをセットする前に非同期の処理を行えるようにするために asyncData メソッドを追加しています。

参照: https://ja.nuxtjs.org/guide/async-data/

# 手順
## 前準備
- `npm install xml2js`
    - XMLを扱うのでparseしてくれるモジュールinstallしておく

## コンポーネントを用意する
`pages/rss.vue`という名前のpageコンポーネントを用意します
先に完成形を↓↓

```js:pages/rss.vue
<template>
  <div>
    <ul>
      <li v-for="item in data">
        <a v-bind:href="item.link">
          {{item.title}}
        </a>
      </li>
    </ul>
  </div>
</template>

<script>
  export default {
    asyncData ({params}, callback) {
      axios.get(`RSSのURL`)
        .then((res) => {
          var parseString = require('xml2js').parseString
          var xml = res.data
          parseString(xml, (message, xmlres) => {
            callback(null, {data: xmlres.rss.channel[0].item})
          })
        })
        .catch((e) => {
          callback({ statusCode: 404, message: 'ページが見つかりません' })
        })
    }
  }
</script>

<style>
</style>
```

部分的に説明していきます

### まず、`asyncData() {}`を用意します
非同期処理を行ってくれます

```js:pages/rss.vue
<script>
  export default {
    asyncData ({params}, callback) {　// ←非同期処理をしてくれる関数
    }
  }
</script>
```

### XMLを取得していきます
今回はaxiosを使っています
取得した結果は`res.data`のオブジェクトに格納されます

```js:pages/rss.vue
<script>
  export default {
    asyncData ({params}, callback) {
      axios.get(`RSSのURL`)
        .then((res) => {
          console.log(res.data) // xmlが入ってる
        })
        .catch((e) => {
        })
    }
  }
</script>
```

### XMLをparseします

```js:pages/rss.vue
          var parseString = require('xml2js').parseString
          var xml = res.data // XML入ってる
          parseString(xml, (err, xmlRes) => {
　　　　　   console.log(xmlRes) // xmlResはXMLをオブジェクトに変換した形
          })
```

前準備でいれた`xml2js`を使って取得したXMLをparseします


### 書き出しの時に扱えるようにdataに登録する

```js:pages/rss.vue
          parseString(xml, (err, xmlRes) => {
　　　　　   callback(null, {data: xmlres.rss.channel[0].item})
          })
```

`callback(null, {<変数名>: <データ>})` とすることで
変数に登録できます
今回の場合、`<template>`のところで使います



### XMLが無かったときの処理

```js:pages/rss.vue
        .catch((e) => {
          callback({ statusCode: 404, message: 'ページが見つかりません' })
        })
```

XMLが取得できなかったときの事を考え
取得できなかったら,４０４を返すようにします

### ビューに書き出す
あとはお好みでいい感じに書き出してください

```js:pages/rss.vue
<template>
  <div>
    <ul>
      <li v-for="item in data">
        <a v-bind:href="item.link">
          {{item.title}}
        </a>
      </li>
    </ul>
  </div>
</template>
```

## 実際にやった結果
適当な[RSS](https://rss.allabout.co.jp/aa/latest/ch/health/)を読み込み元として
http://localhost:3000/rss/ にアクセスした結果がこちら

![スクリーンショット 2017-12-19 14.22.20.png](https://qiita-image-store.s3.amazonaws.com/0/108154/a20ade42-ebd9-158c-3a03-0f730bc34955.png)

無事取得できてますねー
こんなかんじでズラ～と出てきます

## [おまけ]URLに応じて読み込むRSSを変えたい時

`pases/category/_name.vue`を作った時
Nuxt.jsは `http://localhost:3000/category/<なんか>/`
というルーティングを作ってくれます
参照: https://ja.nuxtjs.org/guide/routing#動的なルーティング

その`<なんか>`の部分を使ってRSSの読み込み先を変更することも可能です

サンプル↓↓

```js:pases/category/_name.vue
<script>
  import axios from 'axios'

  export default {
    asyncData ({params}, callback) {
      axios.get(`https://rss.allabout.co.jp/aa/latest/ch/${params.name}`)
        .then((res) => {
          var parseString = require('xml2js').parseString
          var xml = res.data
          parseString(xml, (message, xmlres) => {
            callback(null, {data: xmlres.rss.channel[0].item})
          })
        })
        .catch((e) => {
          var result = { statusCode: 404, message: 'ページが見つかりません' }
          callback(result)
        })
    }
  }
</script>
```

`${params.name}`でURL上の引数を取得することが出来ます、便利！

# まとめ
ブラウザへのレンダリング前に実行してくれるasyncDataは
非同期処理のことを考える手間を減らしてくれて最高です

Vue.jsには無かったメソッドな気がする(別でnpm installすればある)ので
コレだけでもNuxt.jsを使いたくなりますね