web-dev-qa-db-ja.com

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

だから私は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コンポーネント内で、created()初期化フックでthis.initialPropertiesthis.data.propertiesに割り当てています。そして、それは機能し、反応的です。

// 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>

しかし、それに関する私の問題は、それが正しい方法かどうかわからないということです。それは私に道に沿ったいくつかのトラブルを引き起こしませんか?またはそれを行うためのより良い方法はありますか?

59
Dominik Serafin

これに感謝 https://github.com/vuejs/vuejs.org/pull/567 私は今答えを知っています。

方法1

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

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

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

警告:この方法は推奨されません。コンポーネントが予測不能になります。子コンポーネントから親データを設定する必要がある場合は、Vuexなどの状態管理を使用するか、「v-model」を使用します。 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/

59
Dominik Serafin

ドキュメントに記載されているとおりであるため、あなたはそれを正しく行っていると思います。

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

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

10
jonan.pineda

@ dominik-serafinの回答と合わせて:

Opbjectを渡す場合、スプレッド演算子(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/[email protected]/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/

9
Igor Parra