Vue.js 2の初期データとして小道具を渡す正しい方法は何ですか?


97

したがって、小道具をVueコンポーネントに渡したいのですが、これらの小道具は将来、そのコンポーネントの内部から変更されることを期待しています。たとえば、AJAXを使用して内部からそのVueコンポーネントを更新した場合です。したがって、これらはコンポーネントの初期化のみを目的としています。

私のcars-list私は初期特性と小道具を渡すVueの構成要素single-car

// cars-list.vue

<script>
    export default {
        data: function() {
            return {
                cars: [
                    {
                        color: 'red',
                        maxSpeed: 200,
                    },
                    {
                        color: 'blue',
                        maxSpeed: 195,
                    },
                ]
            }
        },
    }
</script>

<template>
    <div>
        <template v-for="car in cars">
            <single-car :initial-properties="car"></single-car>
        </template>
    </div>
</template>

私が今それを行う方法は、私のsingle-carコンポーネント内でon 初期化フックに割り当てthis.initialPropertiesているということです 。そしてそれは機能し、反応します。this.data.propertiescreated()

// single-car.vue

<script>
    export default {
        data: function() {
            return {
                properties: {},
            }
        },
        created: function(){
            this.data.properties = this.initialProperties;
        },
    }
</script>

<template>
    <div>Car is in {{properties.color}} and has a max speed of {{properties.maxSpeed}}</div>
</template>

しかし、それに関する私の問題は、それが正しい方法であるかどうかわからないということですか?道に迷惑をかけてしまいませんか?それとももっと良い方法がありますか?


13
すべては:これは私の意見でのVueについて最も混乱ものですdataされてtwo-wayバインドされていますが、渡すことはできませんdataコンポーネントに、あなたは合格propsしていますが、受信変更することはできませんpropsや変換propsdata。じゃあ何?私が学んだことの1つは、propsイベントを継承してトリガーする必要があるということです。つまり、コンポーネントがprops受け取ったものを変更したい場合は、イベントを呼び出して「レンダリング」する必要があります。しかし、one-wayReactとまったく同じバインディングが残っているので、その用途はわかりませんdata。かなり混乱しています。
アンドレ・ペーニャ

1
データは主にコンポーネントの私的使用を目的としています。コンポーネントのコンテキスト内に配置されたものはすべて反応性があり、バインドできます。propsの概念は、コンポーネントに値を渡すことですが、コンポーネントは、渡された値を変更することによって、親の状態変更を静かに導入できないようにします。指定したとおり、イベントで明示的にすることをお勧めします。これは、Vue 1.0から2.0への哲学の変更でした。
David K. Hess

今日はこっちスレッドを開始しようとしました:forum.vuejs.org/t/...
bgraves

回答:


102

これのおかげでhttps://github.com/vuejs/vuejs.org/pull/567私は今答えを知っています。

方法1

初期小道具を直接データに渡します。更新されたドキュメントの例のように:

props: ['initialCounter'],
data: function () {
    return {
        counter: this.initialCounter
    }
}

ただし、渡されたプロップが親コンポーネントの状態で使用されるオブジェクトまたは配列である場合、そのプロップを変更すると、その親コン​​ポーネントの状態が変化することに注意してください。

警告:この方法はお勧めしません。コンポーネントが予測不可能になります。子コンポーネントから親データを設定する必要がある場合は、Vuexなどの状態管理を使用するか、「vモデル」を使用します。https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components

方法2

最初の小道具がオブジェクトまたは配列であり、子の状態の変更を親の状態に反映させたくない場合は、次のように、たとえばVue.util.extend[1]を使用して、小道具のデータを直接指すのではなく、小道具のコピーを作成します。

props: ['initialCounter'],
data: function () {
    return {
        counter: Vue.util.extend({}, this.initialCounter)
    }
}

方法3

スプレッドオペレーターを使用して、小道具のクローンを作成することもできます。イゴールの回答の詳細:https : //stackoverflow.com/a/51911118/3143704

ただし、スプレッド演算子は古いブラウザではサポートされておらず、互換性を高めるために、たとえばを使用してコードをトランスパイルする必要があることに注意してくださいbabel

脚注

[1]これはVueの内部ユーティリティであり、新しいバージョンで変更される可能性があることに注意してください。他のメソッドを使用してその小道具をコピーすることもできます。JavaScriptオブジェクトを正しく複製するにはどうすればよいですか?参照してください。

私がそれをテストしていた私のフィドル:https : //jsfiddle.net/sm4kx7p9/3/


1
変更を親コンポーネントに伝播させることは大丈夫ですか?
igor

1
@igor個人的には、できるだけ回避するようにします。コンポーネントが予測不可能になります。親コンポーネントの変更を取得するより良い方法は、子コンポーネントから親コンポーネントへの変更を$ emitする "v-model"メソッドを使用することだと思います。vuejs.org/v2/guide/components.html#Using-v-model-on-Components
ドミニクセラフィン

はい、しかし深いオブジェクトはどうですか?ディープコピーする必要がありますか?ディープオブジェクトを使用しないようにコンポーネントを再設計する必要がありますか?つまり、以下のプロップを{ ok: 1, notOk: { meh: 2 } }使用します。以前のクローン作成方法のいずれかで内部データを設定した場合でも、プロップが変更されますnotOk.meh
Nikso

1
素晴らしい質問と回答をありがとう@DominikSerafin。これはVue.jsのアキレス腱を完全に示しています。フレームワークとしてコンポーネント化をうまく処理しますが、カンプ間でデータを渡すことが主要なPITAです。作成された用語の悪夢を見てください。だから今私はすべての小道具に接頭辞を付けてinitial、コンプ内でそれらを使用できるようにする必要があります。data任意のコンプに呼び出されたプロップを渡して、ローカライズされたデータをこのinitialPropName狂気のない状態で自動的に伝播させることができれば、はるかにクリーンになります。
AJB

1
@DominikSerafin私はあなたが言っていることを聞いています、そしてあなたは間違っていません。しかし、Vue.jsを使用してフォームビルダーアプリを作成すれば、私が何を意味するかがすぐにわかります。私は実際、データを共有する手法prop --> comp.dataすべてのデータに対してVue-Stashを使用するように変更する過程にあります(またはVuexも機能します)。しかし、今はwindow、「モダンな」JSフレームワークが私に意見を課す前に行っていたように、オブジェクトからデータをバウンスしているだけです。だから、それは質問をします:comp.dataプロパティのポイントは何ですか?
AJB

24

@ dominik-serafinの答えと一緒に:

オブジェクトを渡す場合は、spread演算子(ES6構文)を使用して簡単にオブジェクトを複製できます。

 props: {
   record: {
     type: Object,
     required: true
   }
 },

data () { // opt. 1
  return {
    recordLocal: {...this.record}
  }
},

computed: { // opt. 2
  recordLocal () {
    return {...this.record}
  }
},

ただし、最も重要なのは、optを使用することを忘れないことです。2は、計算値またはそれ以上の非同期値を渡す場合に使用します。そうでない場合、ローカル値は更新されません。

デモ:

Vue.component('card', { 
  template: '#app2',
  props: {
    test1: null,
    test2: null
  },
  data () { // opt. 1
    return {
      test1AsData: {...this.test1}
    }
  },
  computed: { // opt. 2
    test2AsComputed () {
      return {...this.test2}
    }
  }
})

new Vue({
  el: "#app1",
  data () {
    return {
      test1: {1: 'will not update'},
      test2: {2: 'will update after 1 second'}
    }
  },
  mounted () {
    setTimeout(() => {
      this.test1 = {1: 'updated!'}
      this.test2 = {2: 'updated!'}
    }, 1000)
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id="app1">
  <card :test1="test1" :test2="test2"></card>
</div>

<template id="app2">
  <div>
    test1 as data: {{test1AsData}}
    <hr />
    test2 as computed: {{test2AsComputed}}
  </div>
</template>

https://jsfiddle.net/nomikos3/eywraw8t/281070/


@ igor-parraさん、重複した回答を送信したようです。また、spreadオペレーターはすべてのブラウザーでサポートされているわけではなく、互換性を高めるためにトランスパイルの手順が必要になる場合があることにも言及しておくとよいでしょう。それ以外の場合は見栄えが良い-この代替方法を追加してくれてありがとう!
ドミニクセラフィン2018

@ dominik-serafinはい、そうです。ES6への参照を追加しました。Webpackベースのアプリケーションでは、最新のjavascriptを最大限に活用するためにbabelを事前に構成するのは非常に簡単です。
Igor Parra

recordLocal: [...this.record](私の場合、レコードは配列です)私にとってはうまくいきませんでした-Vueコンポーネントをロードして検査した後record、アイテムを含みrecordLocal、空の配列でした。
クリスチャン

COMPUTEDプロパティを使用してもうまくいきますが、データ内に設定しようとすると機能しません=(...しかし、使用しましたcomputed
felipe muner

気をつけて。スプレッド演算子は浅いクローンのみなので、オブジェクトまたは配列を含むオブジェクトの場合は、新しいコピーを取得する代わりにポインタをコピーします。lodashのcloneDeepを使用しています。
シンディコンウェイ

13

私はあなたがそれをドキュメントで述べられているものだから、あなたはそれを正しくやっていると信じています。

プロップの初期値を初期値として使用するローカルデータプロパティを定義する

https://vuejs.org/guide/components.html#One-Way-Data-Flow


4
値渡しの小道具の場合は問題ありません。この場合はオブジェクトなので、変更すると親に影響します。そのページから:「JavaScriptのオブジェクトと配列は参照によって渡されるため、propが配列またはオブジェクトの場合、子コンポーネント内でオブジェクトまたは配列自体を変更すると、親の状態に影響します。」
ジェイク

これは私にとってはうまくいき、明確に文書化されています。上記の回答のこの行は、「警告:この方法はお勧めできません。コンポーネントを予測できなくなります。子コンポーネントから親データを設定する必要がある場合は、Vuexなどの状態管理を使用するか、 "v-model"。 "
Nathaniel Rink

したがって、4年と数百時間の学習曲線の後で、windowオブジェクトから変数を跳ね返し始めたところに戻ってきました。
AJB
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.