Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

【vue.js】mountedでリロード時にapiを叩く処理でthisの取り扱いにハマった

mountedを使って画面読み込み時にapiから取得した値をreleasesオブジェクトにバインディングしたかったけど、thisのスコープを理解していないためハマった。

成功例

キモは次の.bind(this)である。ここでbind関数を指定しない場合、mounted内のthisはwindowオブジェクトを参照してしまう。

this.releases = response.data;
          }.bind(this))
index.html.erb

 <ul>
  <li class="content" v-for="(release, index) in releases" v-bind:key="release.id">
    <div class="subContent">
      <img class="content-image" v-bind:src="release.image" v-on:click="openModal(index)">
      <h3>{{release.title}}</h3>
      <h3>{{release.name}}</h3>

対応するvueは次の通り。

index.js
document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#app',
    data: {
      releases:{}
    },
    mounted:function(){
        axios.get(`/api/releases`).then(function(response){
          console.log(response);
          for(let i = 0; i < response.data.length; i++) {
            response.data[i].showContent = false;
          }
          this.releases = response.data;
          }.bind(this))
          .catch(function(error) {
            console.log(error);
          });
    },
    methods:{
      openModal: function(index){
        //console.log(this.releases[index].showContent)
        this.releases[index].showContent = true
      },
      closeModal: function(index){
        this.releases[index].showContent = false
      }

    }
  })
})

image.png

失敗例

index.js
document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#app',
    data: {
      releases:{}
    },
    mounted:function(){
        axios.get(`/api/releases`).then(function(response){
          console.log(response);
          for(let i = 0; i < response.data.length; i++) {
            response.data[i].showContent = false;
          }
          this.releases = response.data;
          })
          .catch(function(error) {
            console.log(error);
          });
    },
    methods:{
      openModal: function(index){
        //console.log(this.releases[index].showContent)
        this.releases[index].showContent = true
      },
      closeModal: function(index){
        this.releases[index].showContent = false
      }

    }
  })
})

typeerrorが出力される。この場合releasesオブジェクトにapiから取得した値をバインディングできていない
image.png

なんで

次の箇所でコールバックさせているのがダメっぽい

mounted:function(){
        axios.get(`/api/releases`).then(function(response){
          console.log(response);
          for(let i = 0; i < response.data.length; i++) {

JavaScript中級者への道【2. 4種類のthis】

hoge関数の引数のcallbackがコールバック関数と呼ばれるものです。
ここで、以下のような形でオブジェクトのメソッドを渡すと失敗します。

// 名前と、それを表示するメソッドを持つオブジェクトを作成する
var obj = {
  name : 'matsuby',
  sayName : function () {
    console.log(this.name);
  }
};

// コールバック関数にメソッドを渡すと…
hoge(obj.sayName);  // => undefined

いつの間にかthisがグローバルオブジェクトを指しているというパターンです。
そこでbind()を使ってthisを任意のオブジェクトに束縛することで解決出来ます。

JavaScript の超便利なメソッド bind で this を制御する
などを読んで対処

thisのスコープには気をつけようね、ということ

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
3
Help us understand the problem. What are the problem?