「小道具」の変更をリッスンする方法


257

VueJs 2.0ドキュメント私が上でリッスンする任意のフック見つけることができませんprops変更を。

VueJにはそのようなフックがありonPropsUpdated()ますか?

更新

@wostexが示唆したように、私はwatch自分の財産を試しましたが、何も変わりませんでした。それから私は特別なケースがあることに気づきました:

<template>
    <child :my-prop="myProp"></child>
</template>

<script>
   export default {
      props: ['myProp']
   }
</script>

myProp親コンポーネントがコンポーネントに受け取ることを渡しchildます。その後、watch: {myProp: ...}動作していません。



1
私はあなたのケースを正しく理解しているとは思いません。あなたの正確な目標は何ですか?「何かが起こったとき、私は何かがここで(どこで?)起きるのを望んでいる」。親プロップ値を手動で変更しようとしていますか?はいの場合、これはまったく別のケースです。
Egor Stambakio 2017年

@wostex、これがCodePenです。悪い点は、ペンで機能していることです...
Amio.io

1
なるほど、問題はどこか別のところにあります。コードを見せてください。
Egor Stambakio 2017年

1
こんにちは。ここで:ChannelDetail.vueあなたがFacebookPageDetailコンポーネントの任意の場所をインポートし、それを宣言しない:gist.github.com/zatziky/...私はFacebookChannelDetail.vueは、それが正常に見えるよりもFacebookPageDetailその他としてChannelDetail.vueにインポートする必要がありますね
Egorスタンバキオ2017年

回答:


321

watch小道具の変更時にいくつかのコードを実行する小道具をすることができます:

new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  },
  components: {
    'child' : {
      template: `<p>{{ myprop }}</p>`,
      props: ['myprop'],
      watch: { 
      	myprop: function(newVal, oldVal) { // watch it
          console.log('Prop changed: ', newVal, ' | was: ', oldVal)
        }
      }
    }
  }
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>

<div id="app">
  <child :myprop="text"></child>
  <button @click="text = 'Another text'">Change text</button>
</div>


1
wostex用のThx、私はすでに試しましたwatch。あなたの例のせいで、私の場合は少し違うことに気づきました。質問を更新しました。
Amio.io 2017年

1
それがcomponentWillReceiveProps()のように見えるのを見てください。たとえば:D
yussanの

@yussanはい、ただし、追跡する必要がある1つの小道具に適用されます。
エゴールスタンバキオ2018年

1
通常、計算されたプロパティを使用する方が良いので、時計は推奨されませんが、時計の使用にパフォーマンスの問題はありますか?
SethWhite 2018年

1
@SethWhite オブザーバーパターンを使用してVueで反応性がどのように処理されるかについて私が理解していることから、ウォッチャーは、計算されたデータや他の反応データよりも必ずしも効率的ではありません。プロパティの値が多くの値に依存する場合、計算されたプロップは、結果が依存する各値に対して、単一の関数と個別の監視コールバックを実行します。ほとんどの一般的なユースケースでは、計算されたプロパティが望ましい結果をもたらすと思います。
plong0 2018年

83

これを試しましたか?

watch: {
  myProp: {
    // the callback will be called immediately after the start of the observation
    immediate: true, 
    handler (val, oldVal) {
      // do your stuff
    }
  }
}

https://vuejs.org/v2/api/#watch


7
これは私にとってはうまくいきましたが、答えはうまくいきませんでした-多分それは更新です。ありがとう、BearInBox :)
Grant

2
即時:trueで修正済み
basbase

2
このように時計を設定すると、私にとってもそれが修正されました、ありがとう!
adamk22

2
私もうまくいきます。これは受け入れられる答えになるはずです
titou10

1
受け入れられた答えがしなかったのに対し、私のためにも働きました。+1
ロベルト

25

彼、

私の場合、小道具が変わるたびにデータを再度解析する必要があるソリューションが必要でした。私はすべての小道具のために別のウォッチャーを作るのに疲れていたので、これを使用しました:

  watch: {
    $props: {
      handler() {
        this.parseData();
      },
      deep: true,
      immediate: true,
    },

この例から取り上げる重要なポイントは、deep: true$ propsを監視するだけでなく、ネストされた値などを使用することです。props.myProp

この拡張ウォッチオプションの詳細については、https//vuejs.org/v2/api/#vm-watchをご覧ください。


お支払いいただきありがとうございます。幸運を!
JoeSchr

7

あなたが持っているコンポーネント階層と小道具を渡す方法を理解する必要があります、間違いなくあなたのケースは特別であり、通常開発者が遭遇することはありません。

親コンポーネント-myProp->子コンポーネント-myProp->孫コンポーネント

myPropが親コンポーネントで変更れると、子コンポーネントにも反映されます。

そしてmyPropが子コンポーネントで変更された場合、それが反映されます、孫コンポーネントにもれます。

したがって、myPropが親コンポーネントで変更されると、反映されます、孫コンポーネントにれます。(ここまでは順調ですね)。

したがって、階層を下っていくと、小道具は何もする必要がなくなり、本質的に反応します。

階層を上ることについて話します

myPropがgrandChildコンポーネントで変更された場合、反映されません。、子コンポーネントにはれ。子で.sync修飾子を使用し、grandChildコンポーネントからイベントを発行する必要があります。

myPropが子コンポーネントで変更された場合、親コンポーネントには反映さません。親で.sync修飾子を使用し、子コンポーネントからイベントを発行する必要があります。

myPropがgrandChildコンポーネントで変更された場合、反映されません。、(明らかに)親コンポーネントにはれ。.sync修飾子を使用し、孫コンポーネントからイベントを発行してから、子コンポーネントのプロップを監視し、.sync修飾子を使用して親コンポーネントによってリッスンされている変更時にイベントを発行する必要があります。

混乱を避けるためにいくつかのコードを見てみましょう

Parent.vue

<template>
    <div>
    <child :myProp.sync="myProp"></child>
    <input v-model="myProp"/>
    <p>{{myProp}}</p>
</div>
</template>

<script>

    import child from './Child.vue'

    export default{
        data(){
            return{
                myProp:"hello"
            }
        },
        components:{
            child
        }
    }
</script>

<style scoped>
</style>

Child.vue

<template>
<div>   <grand-child :myProp.sync="myProp"></grand-child>
    <p>{{myProp}}</p>
</div>

</template>

<script>
    import grandChild from './Grandchild.vue'

    export default{
        components:{
            grandChild
        },
        props:['myProp'],
        watch:{
            'myProp'(){
                this.$emit('update:myProp',this.myProp)

            }
        }
    }
</script>

<style>

</style>

Grandchild.vue

<template>
    <div><p>{{myProp}}</p>
    <input v-model="myProp" @input="changed"/>
    </div>
</template>

<script>
    export default{
        props:['myProp'],
        methods:{
            changed(event){
                this.$emit('update:myProp',this.myProp)
            }
        }
    }
</script>

<style>

</style>

しかし、この後、Vueの叫び声の警告に気付かずにはいられません。

「親コンポーネントが再レンダリングされるたびに値が上書きされるため、プロップを直接変更しないでください。」

先に述べたように、これはアンチパターンであるため、ほとんどの開発者はこの問題に遭遇しません。そのため、この警告が表示されます。

しかし、あなたの問題を解決するために(あなたの設計に従って)。私はあなたが上記の作業を回避する必要があると信じています(正直に言うとハック)。私はまだあなたにあなたのデザインを再考するべきであり、makeがバグを起こしにくいことを勧めます。

お役に立てば幸いです。


6

あなたがそれを解決したかどうか(そして私が正しく理解しているかどうか)はわかりませんが、これが私の考えです:

親がmyPropを受け取り、それを子に渡して子で監視する場合、親はmyProp(参照ではない)のコピーを持っている必要があります。

これを試して:

new Vue({
  el: '#app',
  data: {
    text: 'Hello'
  },
  components: {
    'parent': {
      props: ['myProp'],
      computed: {
        myInnerProp() { return myProp.clone(); } //eg. myProp.slice() for array
      }
    },
    'child': {
      props: ['myProp'],
      watch: {
        myProp(val, oldval) { now val will differ from oldval }
      }
    }
  }
}

そしてhtmlで:

<child :my-prop="myInnerProp"></child>

実際には、そのような状況で複雑なコレクションに取り組むときは非常に注意する必要があります(数回受け継がれる)


良いアイデア。現時点では検証できません。再びvueで作業するときに確認します。
Amio.io 2017年

1
@ m.cichaczに感謝します。同じ間違いをして、コピーを子に渡すようにとの提案のおかげですぐに修正しました
undefinederror

4

双方向バインディングの場合、.sync修飾子を使用する必要があります

<child :myprop.sync="text"></child>

詳細...

変更をリッスンして更新するには、子コンポーネントの監視プロパティを使用する必要があります

props: ['myprop'],
  watch: { 
    myprop: function(newVal, oldVal) { // watch it
      console.log('Prop changed: ', newVal, ' | was: ', oldVal)
    }
  }

確かに、これは子コンポーネントの小道具の変更を監視する新しい方法です。
Amio.io 2018

2

私は次のような計算されたプロパティを扱います:

    items:{
        get(){
            return this.resources;
        },
        set(v){
            this.$emit("update:resources", v)
        }
    },

この場合、リソースはプロパティです。

props: [ 'resources' ]

1

私にとってこれは1つの特定のプロップ変更を取得し、それを使用してロジックを作成するための丁寧なソリューションです

私が使用するpropsと、変数のcomputed変更を受け取るために後にロジックを作成するためのプロパティ

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
  objectDetail: { // <--- we could access to this value with this.objectDetail
    type: Object,
    required: true
  }
},
computed: {
  _objectDetail: {
    let value = false
    // ...
    // if || do || while -- whatever logic
    // insert validation logic with this.objectDetail (prop value)
    value = true
    // ...
    return value 
  }
}

したがって、html renderで_objectDetailを使用できます

<span>
  {{ _objectDetail }}
</span>

またはいくつかの方法で:

literallySomeMethod: function() {
   if (this._objectDetail) {
   ....
   }
}

0

監視モードを使用して、変更を検出できます。

原子レベルですべてを行います。そのため、最初に内部を監視することで、watchメソッド自体が呼び出されているかどうかを確認します。時計が呼び出されていることが確認されたら、ビジネスロジックでそれを打ち破ります。

watch: { 
  myProp: function() {
   console.log('Prop changed')
  }
}

0

変更を受け取るためにロジックを作成する必要がある場合はprops、変数のcomputedプロパティを使用します

export default {
name: 'getObjectDetail',
filters: {},
components: {},
props: {
    objectDetail: {
      type: Object,
      required: true
    }
},
computed: {
    _objectDetail: {
        let value = false
        ...

        if (someValidation)
        ...
    }
}

-1

myPropがオブジェクトの場合、通常は変更されない場合があります。したがって、時計はトリガーされません。myPropが変更されない理由は、ほとんどの場合、myPropのいくつかのキーを設定するだけだからです。myProp自体はまだ1つです。"myProp.a"のようなmyPropのプロップを監視しようとすると、機能するはずです。


-1

監視機能は子コンポーネントに配置する必要があります。親ではありません。


-1

@JoeSchrは良い答えを持っています。これは、「deep:true」を使用したくない場合に行う別の方法です。

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.