プログラミング技術

本サイトはプロモーションが含まれています。

Vue/Nuxt.jsでslotで子コンポーネントの情報を親から書き換える

vue/Nuxtでslotを利用
初心者さん
呼び出し元によって子コンポーネントで表示する内容が違う!どうしよう

Vue/Nuxt.jsを使っているとよくある悩みです。今回はこのような悩みを解決していきます。

解決策はいくつかありますよね。例えば、

  1. propsで値を渡す
  2. storeを使う
  3. slotで親から子コンポーネントに表示する内容を置き換える

この記事では、このあたりについて書いていきます。

propsはよく使うので、使い所に困ることはないと思いますが、slotを使った方がいい感じになる部分もあるので紹介します。

親コンポーネントから子コンポーネントを制御する方法のおさらい

冒頭に述べたように親から子コンポーネントに値を渡したり、制御する方法はいくつかあります。

props、store(Vuex)、slotがそれに当たります。

それぞれの機能をおさらいをしていきたいと思います。

Vue/Nuxt.jsでよく使うpropsという機能

Vue/Nuxt.jsでは、共通で使う機能をコンポーネント化して呼び出せるようにしますね。その時に、そのコンポーネントに親から値を渡すことができます。その機能がpropsになります。

propsにもメリットとデメリットがありますね。

propsのメリット

親から子に値を渡すだけであれば、propsは簡単に使える、コードが複雑になりにくいなどのメリットがあります。

propsのデメリット

逆にデメリットは、親から子、さらに孫などまでいくとデータの管理がしにくいなどでしょう。

propsを使ったサンプルコード

親コンポーネントから「Child1」という子コンポーネントにtitleを渡すだけです。以下のような簡単なコンポーネントであれば、propsを選択するのが最善かと思います。

親コンポーネント

<template>
  <Child1 :title="title" />
</template>

<script>
import Child1 from '../components/Child1'

export default {
  components: {
    Child1
  },
  data() {
    return {
      title: "親から渡したTitle"
    }
  }
}
</script>

【Child1】子コンポーネント

<template>
  <h2>{{title}}</h2>
</template>

<script>
export default {
  props: {
    title: {
      type: String,
      default: ''
    }
  }
}

Vue/Nuxt.jsのstoreでデータ管理を行う

storeの場合は、propsが苦手な親から子、孫とデータの管理が必要な場合に使われることが多い機能ですね。

storeといっても一つのjsファイルをインポートして利用するため、コンポーネントがstoreに依存することになります。

いろんなところから呼び出されるコンポーネントの場合、storeに依存した作りになっていると使いにくくなります。

▼storeって言ってますが、Vuexのことです。以下に簡単な説明記事があるので、ご覧ください。

Vue/Nuxt.jsのslotってどんな機能?

slotってどんな機能なのかVue/Nuxt.jsを始めたばかりの人はあまり知られていない機能かもしれません。

自分も半年くらいは業務でも使いませんでした、というかあまり使いみちがわからなかったという状況でした。

slotとは

slotがどんな機能か簡単に説明すると、親コンポーネントから子コンポーネントに表示させるものを制御する機能です。

文字だけであれば、propsとの違いがわからないのでサンプルコード見たほうが早いと思うので以下をご覧ください。

slotを使ったサンプルコード

例えば、【1つ目の】親コンポーネントでは、親コンポーネントから子コンポーネントの「slotタグ」の部分にボタンを2つ渡しています。

【2つ目の】親コンポーネントも同様に子コンポーネントの「slotタグ」の部分にボタンを3つ渡しています。

【1つ目の】親コンポーネント

<template>
  <Child1>
    <template v-slot:btnBox>
      <button type="button">cancel</button>
      <button type="button" @click="save">save</button>
    </template>
  </Child1>
</template>

<script>
import Child1 from '../components/Child1'

export default {
  components: {
    Child1
  },
  methods: {
    save() {
      console.log('save実行')
    }
  }
}
</script>

【2つ目の】親コンポーネント

<template>
  <Child1>
    <template v-slot:btnBox>
      <button type="button">delete</button>
      <button type="button">cancel</button>
      <button type="button" @click="saveDialog">save</button>
    </template>
  </Child1>
</template>

<script>
import Child1 from '../components/Child1'

export default {
  components: {
    Child1
  },
  data() {
    return {
      
    }
  },
  methods: {
    saveDialog() {
      alert('保存しますか?')
    }
  }
}
</script>

【Child1】子コンポーネント

<template>
  <div>
    <slot name="btnBox"></slot>
  </div>
</template>

サンプルコードでslotを使うと効率が良い理由

上記のサンプルコードでslotを使って良いと思うのは、いくつかあります。

  • 表示させたいボタンが違うため、親から制御するだけでいい点
  • 同じsaveボタンでも呼び出したいメソッドが違う。(子コンポーネントにそれぞれのメソッドを書かなくてもいい)

slotの使い場所は限定的になるかもしれませんが、知っていると悩まずに実装できることも多いので、どんな機能かくらいは理解しておくといいと思います。

まとめ

store(Vuex)でデータの管理をするにしてもpropsを使うにしても、コンポーネントの設計が重要ですね。

「そもそもコンポーネントの設計が悪いからslot使わないといけなくなるのでは?」とかいう話になるかもしれませんが、機能実装した時には想定されていなかった変更はよくあることです。

いろんな引き出しを持っているのは、エンジニアとして重要かと思いました。

今回は以上となります。備忘録兼ねての内容なのでご理解ください。

-プログラミング技術