質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.34%

スロットプロパティには好きな名前は使えないのでしょうか?

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 473

stadmlmg

score 12

お世話になります。
現在Vue.jsを勉強中で、ドキュメントに目を通しています。
スロットの説明で理解できない部分があります。
どなたかご教示いただけると大変ありがたいです。

不明点

ガイドのスロットの章「その他の例」の説明に関してなのですが、この部分の説明は「isCompleteがtrueのタスクに関しては先頭に✓をつける」というUIの操作を、親コンポーネントから行っているケースだと解釈しています。

ここで、親コンポーネントの<template v-slot:todo="{ todo }">{ todo }の記述の部分が、同じドキュメント内でも説明のあるスロットプロパティであると認識しています。

<todo-list v-bind:todos="todos">
  <template v-slot:todo="{ todo }">
    <span v-if="todo.isComplete"></span>
    {{ todo.text }}
  </template>
</todo-list>


スロットプロパティの説明では

すべてのスロットプロパティを保持するオブジェクトの名前を slotProps にしましたが、あなたの好きな名前を使うことができます。

とあるので、ドキュメントのコードを動く形にし、自分の好きなスロットプロパティ名に変更してみたところ、エラーで画面が真っ白になってしまいました。
※コード内がtodoだらけでどこになんの値が反映されているのか分かりずらかったので、変更できる部分は変更してみようと思ったのが発端です

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Vue Document</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
</head>
<body>

    <div id="app">


        <todo-list v-bind:todos="todos">
            <template v-slot:todo="{ acceptAnySlotPropertyName }"><!-- スロットプロパティの名前はなんでも良いはず -->
                <span v-if="acceptAnySlotPropertyName.isComplete"></span>
                {{ acceptAnySlotPropertyName.text }}
            </template>
        </todo-list>
    </div>


    <script>
    Vue.component('todo-list', {
    data: function(){
        return {
            filteredTodos: [ 
                { id: '1', text: 'ID1のテキスト', isComplete: true },
                { id: '2', text: 'ID2のテキスト', isComplete: false },
                { id: '3', text: 'ID3のテキスト', isComplete: true }
            ]
        }
    },
    props:['todos'],
    template: `
        <ul>
            <li
                v-for="todo in filteredTodos"
                v-bind:key="todo.id"
            >
                <slot name="todo" v-bind:todo="todo">
                <!-- フォールバックコンテンツ -->
                {{ todo.text }}
                </slot>
            </li>
         </ul>
        `
    });

    new Vue({
        el: '#app',
        data: {
            todos: [
                {  },
                {  },
                {  }
            ]
        }
    })
</script>
</body>
</html>


コンソールのエラー内容は下記になります。

[Vue warn]: Error in render: "TypeError: Cannot read property 'isComplete' of undefined"

vue.js:1897 TypeError: Cannot read property 'isComplete' of undefined
    at fn (eval at createFunction (vue.js:11649), <anonymous>:3:194)
    at normalized (vue.js:2597)
    at Proxy.renderSlot (vue.js:2693)
    at eval (eval at createFunction (vue.js:11649), <anonymous>:3:91)
    at Proxy.renderList (vue.js:2637)
    at Proxy.eval (eval at createFunction (vue.js:11649), <anonymous>:3:27)
    at VueComponent.Vue._render (vue.js:3551)
    at VueComponent.updateComponent (vue.js:4067)
    at Watcher.get (vue.js:4478)
    at new Watcher (vue.js:4467)

スロットプロパティの文言と小コンポーネントでバインドしている属性名を一致させると期待通りの表示になるのですが、それだと「好きな名前を使うことができます」というドキュメントの説明と一致しないため疑問に思い質問させていただきました。

そもそもの理解として間違っている部分がありましたらご指摘いただけると幸いです。
何卒よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

すべてのスロットプロパティを保持するオブジェクトの名前を slotProps にしましたが、あなたの好きな名前を使うことができます。

この部分で勘違いをされているようです。

上記の文が意味しているのは、公式ドキュメントのスコープ付きスロットの例で言うと、slotにバインドする属性の名前(v-bind:useruserの部分(1))に関係なく、受け取るオブジェクトの名前(slotProps(2))を決められるということです。

// 子コンポーネント
<span>
  <slot v-bind:user="user"> <!-- (1) -->
    {{ user.lastName }}
  </slot>
</span>
// 親コンポーネント
<current-user>
  <template v-slot:default="slotProps"> <!-- (2) -->
    {{ slotProps.user.firstName }}
  </template>
</current-user>

slotのuser属性にuserという値をバインディングしていますが、それを受け取った親コンポーネントでは、slotProps.userのように使用していることに注目してください。これは、userという値を渡してるように思えて、実際にはuserをプロパティに持つオブジェクトを渡しているということです。

すべてのスロットプロパティを保持するオブジェクトの名前を slotProps にしましたが、あなたの好きな名前を使うことができます。

というのは、「ラッピングするオブジェクトの名前を変えられる」と言う意味です。


ちなみに、stadmlmgさんが試したのは、オブジェクトを受け取るのではなくて、それに含まれるプロパティを、(デフォルトでは同じ名前の)変数として受け取ることです。これは、分割代入と言って、最近のJavaScript(ES2015以降)で可能になった構文です。Vue.jsのbindingのv-bind:xxx="yyy"yyyの部分は純粋なJavaScriptとして解釈されるので、こういったことが可能です。

もしかしたら、以下のようなソースコードを見たことがあるかもしれません。

const obj = {
  myProp: "hello"
}

// 変数myPropにはobj.myPropが代入される
const { myProp } = obj

console.log(myProp) // => hello

公式ドキュメントのslotのページにもスロットプロパティの分割代入として説明されていますので、より詳しく知りたい場合は、そちらをご覧ください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/02/01 10:09 編集

    NozomuIkutaさん回答ありがとうございます。

    自分が勘違いしている部分がよくわかりました。
    「スロットプロパティの分割代入」のドキュメントに目を通したつもりではいたのですが、どうやらきちんと理解できておらず、今回疑問に感じたドキュメント部分でオブジェクトを渡しているものだと勘違いしておりました。

    これは分割代入だったのですね。。。
    きちんと分割代入を理解していれば、よく見れば自分が書いたコードがドキュメントの例と異なり、`{acceptAnySlotPropertyName}`という様に、分割代入で渡してしまっていることに気がつけた様な気がします。

    オブジェクトで渡す場合も、分割代入で渡す場合も両方理解できました。

    本当にありがとうございました。

    キャンセル

  • 2020/02/01 12:53

    解決したようでよかったです。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る