Vue.jsでSPA - [7] Vueからサーバデータ取得

# Vue.jsでSPA - [7] Vueからサーバデータ取得


前回のサーバへのAPIコールをVueの中に入れてく回．今回はスクリーンショットから

## スクリーンショット

リアルデータでそれっぽく動くようになってきたでこれ

![image](https://gyazo.com/1af0a8e341618785e8196933f3b717cd.gif)



## APIコールを入れたコード

長くなってきたがとりあえず貼り付ける．`fetch`をつかうパターン．	

```javascript:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <!-- 1. import Vue router -->
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.1/locale/en.js"></script>
  <link rel="stylesheet" href="../app.css">
</head>


<body>
  <div id="app">
    <el-container>
      <el-header height="100px">
        <img src="../static/img/placeholder-logo-2-300x167.png" height="100" align="left">
      </el-header>
    <el-container>
      <el-aside width="200px">
        <el-col :span="24">
          <el-menu default-active="1" class="el-menu-vertical-demo">
            <el-menu-item index="1">
              <i class="el-icon-location"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/location"><span>Location</span></router-link>
            </el-menu-item>
            <el-menu-item index="2">
              <i class="el-icon-document"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/foo"><span>foo</span></router-link>
            </el-menu-item>
            <el-menu-item index="3">
              <i class="el-icon-setting"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/bar"><span>bar</span></router-link>
            </el-menu-item>
          </el-menu>
        </el-col>
      </el-aside>

     <el-main>
        <!-- 7. The contents will be load here -->
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
  </div>
</body>

<script>

// 2. Define route components.
const Location = { template: '<location-table></location-table>' } // 9. Use the component here
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 3. Define some routes
const routes = [
  { path: '/location', component: Location },
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 4. Create the router instance and pass the `routes` option
const router = new VueRouter({
  routes // short for `routes: routes`
})

// 8. Define component
Vue.component('location-table', {
  data: function() {
    return {
      location: [] // 10-1. location is now initialized as empty - get data from a server!
    }
  },
  created: function() {
    this.getLocation();
  },
  methods: { 
    getLocation: function(){  // 10-2. function for server API call
      let url = 'your-api-endpoint-here';
      fetch(url)
        .then(response => response.json())
        .then(json => {     
            this.location = json.data;  // 10-3. Accessing data in [[PromiseValue]]
            console.log(json.data);
          }) 
        .catch(error => console.error(error))
    }
  },
  template: `
      <el-table :data="location" style="width: 100%">
        <el-table-column prop="id" label="id" width="100"></el-table-column>
        <el-table-column prop="name" label="name"></el-table-column>
        <el-table-column prop="country" label="country" width="180"></el-table-column>
        <el-table-column prop="metro" label="metro" width="180"></el-table-column>
        <el-table-column prop="market" label="market" width="180"></el-table-column>
        <el-table-column prop="status" label="status" width="180"></el-table-column>
      </el-table>
  `
})

ELEMENT.locale(ELEMENT.lang.en)
var vm = new Vue({
  // 5. Inject the router in the Vue instance
  router, 
  el: '#app'
})

</script>

</html>
```



## 前回からの変更点

`Vue.component`の`10-1` `10-2` `10-3`のところ
1. `10-1`はサーバから持ってくるので空にしておいて
2. `10-2`にデータ取ってくるメソッド`getLocation`を定義
3. `10-3`で`created`でインスタンスの準備ができたら`getLocation`をコールする



APIコールをどの時点（`created` or `mounted`）で行うかについてはこの考察が詳しかった：[Vuejs APIアクセスはcreatedとmountedのどちらで行う？](https://qiita.com/kimullaa/items/2bf8948dffb8c52d2b6b)



## 長くなってきたのでファイル分ける

こんなんでいいのかようわからんけど，見にくくなってきたのでコンポーネントのところを分けることにする．おれおれな感じもするが，まあ一応テンプレートとロジック入ってる形で切り出せるし．やっぱり単一ファイルコンポーネント使いやすいように`vue-cli`でやっとくべきだったか...

### メイン側

```html:index.html
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <!-- import CSS -->
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <!-- import Vue before Element -->
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <!-- 1. import Vue router -->
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  <!-- import JavaScript -->
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.4.1/locale/en.js"></script>
  <link rel="stylesheet" href="../../app.css">
</head>


<body>
  <div id="app">
    <el-container>
      <el-header height="100px">
        <img src="../../static/img/placeholder-logo-2-300x167.png" height="100" align="left">
      </el-header>
    <el-container>
      <el-aside width="200px">
        <el-col :span="24">
          <el-menu default-active="1" class="el-menu-vertical-demo">
            <el-menu-item index="1">
              <i class="el-icon-location"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/location"><span>Location</span></router-link>
            </el-menu-item>
            <el-menu-item index="2">
              <i class="el-icon-document"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/foo"><span>foo</span></router-link>
            </el-menu-item>
            <el-menu-item index="3">
              <i class="el-icon-setting"></i>
              <!-- 6. When clicking, it loads the contents defined in 2 and 1 -->
              <router-link to="/bar"><span>bar</span></router-link>
            </el-menu-item>
          </el-menu>
        </el-col>
      </el-aside>

     <el-main>
        <!-- 7. The contents will be loaded here -->
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
  </div>
</body>

<!-- 10. Load components -->
<script src="./location.js"></script>

<!-- Routing and main -->
<script>
// 2. Define route components.
const Location = { template: '<location-table></location-table>' } // 9. Use the component here
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 3. Define some routes
const routes = [
  { path: '/location', component: Location },
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 4. Create the router instance and pass the `routes` option
const router = new VueRouter({
  routes // short for `routes: routes`
})

ELEMENT.locale(ELEMENT.lang.en)
var vm = new Vue({
  // 5. Inject the router in the Vue instance
  router, 
  el: '#app'
})
</script>


</html>        
```

### コンポーネント側

```javascript:location.js
Vue.component('location-table', {
  data: function() {
    return {
      location: [] // 10-1. location is now initialized as empty - get data from a server!
    }
  },
  created: function() {
    this.getLocation();
  },
  methods: {
    getLocation: function(){  // 10-2. function for server API call
      let url = 'your-api-end-point-here';
      fetch(url)
        .then(response => response.json())
        .then(json => {
            this.location = json.data;  // 10-3. Accessing data in [[PromiseValue]]
            console.log(json.data);
          })
        .catch(error => console.error(error))
    }
  },
  template: `
      <el-table :data="location" style="width: 100%">
        <el-table-column prop="id" label="id" width="100"></el-table-column>
        <el-table-column prop="name" label="name"></el-table-column>
        <el-table-column prop="country" label="country" width="180"></el-table-column>
        <el-table-column prop="metro" label="metro" width="180"></el-table-column>
        <el-table-column prop="market" label="market" width="180"></el-table-column>
        <el-table-column prop="status" label="status" width="180"></el-table-column>
      </el-table>
  `
})
```



## 次回

これであとはコンポーネントを増やせばアプリっぽくなっていく感じになってきたので，次は

1. コンポーネント増やしていくか
2. このあたりでどこかクラウドにデプロイしてみるか（サーバレスな感じでやりたい）
3. 1をやりながら`POST`系の動きを書くか

あたりをやってみるかな




## シリーズ

- [Vue.jsでSPA - [1] Element UIでベースの画面をつくる](https://qiita.com/narutaro/items/50d0e4714f93279502c9)
- [Vue.jsでSPA - [2] Element UIで各ペインの画面をつくる](https://qiita.com/narutaro/items/9abbf7881f692c985484)
- [Vue.jsでSPA - [3] vue-routerでルーティング ](https://qiita.com/narutaro/items/74178f4ea031b0ccfa44)
- [Vue.jsでSPA - [4] コンポーネントにしてみる ](https://qiita.com/narutaro/items/df793bb34129d113d9f2)
- [Vue.jsでSPA - [5] リアクティブになってる？](https://qiita.com/narutaro/items/bed4eab6e53e3b46c0b2)
- [Vue.jsでSPA - [6] サーバからのデータ取得](https://qiita.com/narutaro/items/82f4d9635c398524431c)
- [Vue.jsでSPA - [7] Vueからサーバデータ取得](https://qiita.com/narutaro/items/91da194788318c226e0e)
- [Vue.jsでSPA - [8] バックエンドとうまくやっていこうとして試したこと](https://qiita.com/narutaro/items/3b7135eed8f6e930a0e6)
- [Vue.jsでSPA - [9] 今更ながらCORSとそのエラーの回避方法](https://qiita.com/narutaro/items/26e4cbec386bc054bbd7)
- [Vue.jsでSPA - [10] Safari..お前か...3rd party cookie](https://qiita.com/narutaro/items/e53f653d73a6934046d0)
- [Vue.jsでSPA - [11] Element UIでログイン画面](https://qiita.com/narutaro/items/010009c0198371fee658)
- [Vue.jsでSPA - [12] ログイン：シングルペインからツーペインへ画面遷移](https://qiita.com/narutaro/items/fca953b3b2ed5c63360c)
- [Vue.jsでSPA - [13] モバイル向けに OnsenUI に手をだす](https://qiita.com/narutaro/items/bdc0e25c22369466bed3)
- [Vue.jsでSPA - [14] Vue.jsとOnsenUIを使ったオレオレなショッピングカートチュートリアル](https://qiita.com/narutaro/items/9502b90b565366911c57)
- [Vue.jsでSPA - [15] 世界中の人とミーティング時間を決める時に便利なやつ](https://qiita.com/narutaro/items/d6431f54050504bf1551)
- [Vue.jsでSPA - [16] へー、FirebaseでWebアプリのログインってこうやるのか](https://qiita.com/narutaro/items/3c37fe6c3b19a6143a07)