LoginSignup
0
0

More than 1 year has passed since last update.

#1 VueRouterを用いて部分SPA化させる方法

Posted at

app.vueに投稿一覧があり、その投稿の中にあるユーザーの名前をクリックしたらユーザーのページに遷移させるようにしたい。

以前静的なページをVueRouterを用いてそんな感じのことをやったので、その動的なページ版。

router.js

import Vue from 'vue/dist/vue.esm.js'
import VueRouter from 'vue-router'
import Contact from '../components/contact.vue'
import About from '../components/about_coffee_passport.vue'


Vue.use(VueRouter)

export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/contact', component: Contact },
    { path: '/about_coffee_passport', component: About}
  ],
})

before

router.js

import Vue from 'vue/dist/vue.esm.js'
import VueRouter from 'vue-router'
import Contact from '../components/contact.vue'
import About from '../components/about_coffee_passport.vue'
import User from '../components/users/user.vue';

Vue.use(VueRouter)

export default new VueRouter({
  mode: 'history',
  routes: [
    { path: '/contact', component: Contact },
    { path: '/about_coffee_passport', component: About},
    { path: 'user', component: User}
  ],
})

after

こんな感じで記述。

app.vue

          <router-link to="/user">
              <div class="user-info-timeline">
                  <div v-if="drink.user_img">
                     <img class="user-img-timeline" v-bind:src="drink.user_img" > 
                  </div>
                   <div v-else>
                     <img class="user-img-timeline" src ="https://images.unsplash.com/photo-1469334031218-e382a71b716b?ixid=MnwxMjA3fDB8MHxzZWFyY2h8NXx8YnJlYXV0aWZ1bCUyMGdpcmx8ZW58MHx8MHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=700&q=60"> 
                  </div>


                  <div class="username-timeline">
                      {{drink.nickname}}
                  </div>
              </div>
          </router-link>

こんな感じで記述。

hello_vue.js


import VueRouter from 'vue-router'
import router from './router/router'


Vue.use(VueRouter)
Vue.use(router)

と書いたら、

vue.runtime.esm.js:638 [Vue warn]: Error in render: "TypeError: Cannot read properties of undefined (reading 'matched')"

このようにコンソールに出力された。。。

hello_vue.js


document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App),
    router: router
  }).$mount()
  document.body.appendChild(app.$el)

  console.log(app)
})

router: router

この一文を追加すればok.

スクリーンショット 2021-09-06 17.44.57.png

このように表示された。

下準備完了したので実装。

VueRouterで違うコンポーネントを表示させているが、その際にデータの受け渡しとかの記述は必要なのか。。

こーゆー記述あったので、多分必要。

router-linkでparamsを渡すことできるっぽい。

これらを参考に、

router.js
 { path: '/user/:userId', name: 'user',component: User,
app.vue

  <router-link to="{name: 'user', params: {userId: drink.user.id}}">

と書いてみた。

$attrs is readonly.

とエラーがコンソールに表示された。。。

この方の記事の通りで、

hello_vue.jsでは

import Vue from 'vue'

こうやってなってるのに、、

router.js側では

import Vue from 'vue/dist/vue.esm.js'

となってる。

複数のvueインスタンスがつくられてるらしい。

environment.js

environment.config.merge({
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  }
})

にこうやって記述したら、

vue.esm.js:648 [Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.

次はこのようなエラーになった。

at app/javascript/packs/components/footer.vue

footer.vueでエラーが起こり始めた。

一旦これはとばすとして、

hello_vue.js

+import Vue from 'vue/dist/vue.esm.js'
-import Vue from 'vue'

とした。

一旦、router-viewでSPA化できたからokとして、

問題点

スクリーンショット 2021-09-06 22.11.30.png

このように一つ押しただけなのに、全部の投稿のrouter-viewが反応してしまう。。。

app.vue
  <li v-for="drink in drinks" :key="drink.id" class="list" >

このように繰り返してるからねぇ。。

app.vue
 <router-view></router-view>

router-viewの部分に表示されるので、それをv-forの外に置けば済む。

さらなる問題点。。。

問題はユーザーの投稿だけを表示させたいにも関わらず、
```user.vue

export default {
data: function(){
return {
drinks: "drinks"
}
},
created(){
this.setDrink();
},
methods: {
setDrink: function(){
axios.get('/api/drinks')
.then(response =>(
this.drinks = response.data
))
}
}
}
```

このように書いているので、全投稿を取得してしまう。
なぜ全投稿を取得してしまうのかは割愛。

自分が今考えたロジックとしては
全投稿を取得してしまうのはしょうがないとして、
v-on@clickとかなんかで、クリックした要素のuser_idを取得して、
それを子コンポーネントで渡して、
そのidと一致する投稿をthis.drinks
に代入するとか、なんとか。

ってことでクリックした要素を取得するコードを書きます。

router-linkをクリックしたら呼び出したいが、

ここにあるとおり、

このようにしないといけないらしい。

引数にdrinkを渡すことで,drink.user_idで投稿に紐付いてるユーザーのidを取得することができる。

app.vue

 <li v-for="drink in drinks" :key="drink.id"  class="list" >
          <router-link to="/user" @click.native="getUserId(drink)">


methods{
    getUserId(drink){
    console.log(drink)
    }

雑だけど、こんな感じで書いたらいけた!!やったね!!

これをuser.vueの方に渡したい。

app.vue

 <router-view :user_id="user_id"></router-view>

user.vue

  props: {
    user_id: {
      type: Number
    }
  },

と書いたら取得できた。。やったぜ

user.vue

<template>
<div>


 <li v-for="drink in drinks" :key="drink.id"  class="list" >
   {{drink.user_id}}
  </li>
</div>
</template>

<script>

import axios from 'axios';
// import likeButton from './like/likeButton.vue';
// import drinkShow from './drinks/show.vue';


export default {
  props: {
    user_id: {
      type: Number
    }
  },
  data: function(){
    return {
      drinks: "drinks"
    }
  },
  mounted(){
    this.setDrink();
  },
  methods: {
    setDrink: function(){
      axios.get('/api/drinks')
      .then(response =>(
         this.drinks = response.data.filter(drink => 
            drink.user_id = this.user_id
         )
      ))
    }
  }
}
</script>


こんな感じで書いたら、

スクリーンショット 2021-09-07 0.28.16.png

router-link押したときに
 特定の投稿のユーザーだけのidを表示できた。

app.vue

  mounted(){
    this.setDrink();
  },
  methods: {
    setDrink: function(){
      axios.get('/api/drinks')
      .then(response =>(
         this.drinks = response.data.filter(drink => 
            drink.user_id = this.user_id
         )
      ))
    }
  }

createdからmounted()に変更

createdだと処理をするタイミングが早すぎて、this.user_idにアクセスしたときにエラーが起こってしまった。

response.dataに全投稿のデータが入ってるが、
その配列にfilter()メソッドをしてあげることで
条件に一致した要素だけで作られた配列を改めて返してくれる嬉しいメソッド。

drink.user_id(response.data、全投稿のそれぞれのuser_id)と
router-linkクリックしたときにuser.vueに渡されるuser_idが一致した要素のみを返してくれる。
つまり、クリックした投稿に紐付いてるユーザーの投稿しか表示されない!!!
やったぜ!!

って思ったけど、なぜかuser_id 5じゃない投稿もuser_idが5になっていて表示されてしまってる。

user.vue

    setDrink: function(){
      axios.get('/api/drinks')
      .then(response => {
        const drinks = response.data
        this.filteredDrinks = drinks.filter(drink => 
            drink.user_id === this.user_id)
      })
    },

こんな感じで書くんだよ!!!
drink.user_id === this.user_id
にしないといけない。。。
ずっと代入式書いていた。。。
評価式にしないといけなかった。。。。
そっかぁ。。。
やっぱ基礎って大事だと思いました。
した準備は完了したので、明日はデザイン部分をやっていきたいと思いますl

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0