Cách lắng nghe những thay đổi của 'đạo cụ'


257

bên trong tài liệu VueJs 2.0, tôi không thể tìm thấy bất kỳ hook nào nghe đượcprops thay đổi.

VueJs có móc như vậy không onPropsUpdated() hoặc tương tự?

Cập nhật

Như @wostex đề xuất, tôi đã thử watchtài sản của mình nhưng không có gì thay đổi. Sau đó, tôi nhận ra rằng tôi đã có một trường hợp đặc biệt:

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

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

Tôi đang thông qua myProprằng thành phần cha mẹ nhận được cho childthành phần. Sau đó, watch: {myProp: ...}không hoạt động.



1
Tôi không chắc tôi hiểu chính xác trường hợp của bạn. Bạn có thể giải thích mục tiêu chính xác của bạn là gì? "Khi một cái gì đó xảy ra, tôi muốn một cái gì đó xảy ra nghiêm ngặt ở đây (ở đâu?)". Bạn đang cố gắng tự thay đổi giá trị prop cha? Nếu có, đây là trường hợp hoàn toàn khác nhau.
Egor Stambakio

@wostex, đây là CodePen . Điều tệ hại là trong chiếc bút nó đang hoạt động ...
Amio.io

1
Tôi thấy, vấn đề là ở một nơi khác. Cho tôi xem mã của bạn, tôi sẽ xem xét.
Egor Stambakio

1
Xin chào. Ở đây: ChannelDetail.vue bạn không nhập FacebookPageDetail thành phần bất cứ nơi nào, nhưng tuyên bố nó: gist.github.com/zatziky/... Tôi đoán nó nên được FacebookChannelDetail.vue nhập khẩu vào ChannelDetail.vue như FacebookPageDetail Ngoài ra có vẻ tốt đẹp
Egor Stambakio

Câu trả lời:


321

Bạn có thể watchđạo cụ để thực thi một số mã khi thay đổi đạo cụ:

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
Thx cho wostex, tôi đã thử với watch. Do ví dụ của bạn tôi nhận ra rằng trường hợp của tôi hơi khác một chút. Tôi đã cập nhật câu hỏi của tôi.
Amio.io

1
xem nó trông giống như thành
phầnWillReceiveProps

@yussan có, nhưng nó được áp dụng cho một chỗ dựa mà bạn cần theo dõi.
Egor Stambakio

1
Tôi biết đồng hồ không được khuyến khích vì thường sử dụng thuộc tính được tính toán tốt hơn, nhưng có vấn đề gì về hiệu suất khi sử dụng đồng hồ không?
SethWhite

1
@SethWhite Từ những gì tôi hiểu về cách xử lý phản ứng trong Vue bằng cách sử dụng mẫu quan sát viên, người theo dõi không nhất thiết phải kém hiệu quả hơn so với dữ liệu phản ứng hoặc dữ liệu phản ứng khác. Trong trường hợp giá trị của một thuộc tính phụ thuộc vào nhiều giá trị, prop được tính toán sẽ chạy một chức năng duy nhất so với gọi lại theo dõi riêng cho từng giá trị mà kết quả phụ thuộc vào. Tôi nghĩ rằng trong hầu hết các trường hợp sử dụng phổ biến, một thuộc tính được tính toán sẽ có kết quả mong muốn.
plong0

83

Bạn đã thử điều này?

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
Điều này làm việc cho tôi, nơi câu trả lời không - có thể đó là một bản cập nhật. Cảm ơn BearInBox :)
Cấp

2
ngay lập tức: đúng đã sửa nó cho tôi
căn cứ

2
Đặt đồng hồ như thế này là điều cố định nó cho tôi, cảm ơn!
adamk22

2
Làm việc cho tôi quá. Đây phải là câu trả lời được chấp nhận
Titou10

1
làm việc cho tôi quá trong khi câu trả lời được chấp nhận thì không. +1
Roberto

25

Anh ta,

trong trường hợp của tôi, tôi cần một giải pháp trong đó bất cứ lúc nào bất kỳ đạo cụ nào cũng sẽ thay đổi, tôi cần phân tích lại dữ liệu của mình. Tôi đã mệt mỏi với việc làm người theo dõi tách biệt cho tất cả các đạo cụ của mình, vì vậy tôi đã sử dụng điều này:

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

Điểm mấu chốt để lấy đi từ ví dụ này là sử dụng deep: true để nó không chỉ xem các đạo cụ $ mà còn là các giá trị lồng nhau như vdprops.myProp

Bạn có thể tìm hiểu thêm về tùy chọn đồng hồ mở rộng này tại đây: https://vuejs.org/v2/api/#vm-watch


Vui mừng để trả nó về phía trước! Chúc may mắn!
JoeSchr

7

Bạn cần phải hiểu, hệ thống phân cấp thành phần bạn đang có và cách bạn truyền đạo cụ, chắc chắn trường hợp của bạn là đặc biệt và thường không gặp phải bởi các nhà phát triển.

Thành phần phụ huynh -myProp-> Thành phần con -myProp-> Thành phần cháu

Nếu myProp bị thay đổi trong thành phần cha mẹ, nó cũng sẽ được phản ánh trong thành phần con.

Và nếu myProp bị thay đổi trong thành phần con, nó sẽ được phản ánh trong thành phần cháu.

Vì vậy, nếu myProp bị thay đổi trong thành phần cha thì nó sẽ được phản ánh trong thành phần cháu. (càng xa càng tốt).

Do đó, theo thứ bậc, bạn không cần phải làm bất cứ điều gì đạo cụ sẽ phản ứng lại.

Bây giờ nói về việc đi lên trong hệ thống phân cấp

Nếu myProp bị thay đổi trong thành phần grandChild, nó sẽ không được phản ánh trong thành phần con. Bạn phải sử dụng công cụ sửa đổi .sync trong phần tử con và phát ra sự kiện từ thành phần grandChild.

Nếu myProp bị thay đổi trong thành phần con, nó sẽ không được phản ánh trong thành phần chính. Bạn phải sử dụng công cụ sửa đổi .sync trong cha mẹ và phát ra sự kiện từ thành phần con.

Nếu myProp bị thay đổi trong thành phần grandChild, nó sẽ không được phản ánh trong thành phần chính (rõ ràng). Bạn phải sử dụng con sửa đổi .sync và phát ra sự kiện từ thành phần cháu, sau đó xem prop trong thành phần con và phát ra một sự kiện thay đổi đang được nghe bởi thành phần cha mẹ bằng cách sử dụng sửa đổi .sync.

Hãy xem một số mã để tránh nhầm lẫn

Phụ huynh

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

Con.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>

Cháu

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

Nhưng sau đó, bạn sẽ không giúp nhận thấy những cảnh báo la hét của vue nói

'Tránh đột biến prop trực tiếp vì giá trị sẽ bị ghi đè bất cứ khi nào thành phần cha mẹ tái xuất hiện.'

Một lần nữa như tôi đã đề cập trước đó, hầu hết các nhà phát triển không gặp phải vấn đề này, bởi vì đó là một mô hình chống. Đó là lý do tại sao bạn nhận được cảnh báo này.

Nhưng để giải quyết vấn đề của bạn (theo thiết kế của bạn). Tôi tin rằng bạn phải thực hiện các công việc trên (hack phải trung thực). Tôi vẫn khuyên bạn nên suy nghĩ lại về thiết kế của bạn và làm cho ít bị lỗi hơn.

Tôi hy vọng nó sẽ giúp.


6

Không chắc chắn nếu bạn đã giải quyết nó (và nếu tôi hiểu chính xác), nhưng đây là ý tưởng của tôi:

Nếu cha mẹ nhận được myProp và bạn muốn nó truyền cho con và xem nó ở con, thì cha mẹ phải có bản sao của myProp (không tham khảo).

Thử cái này:

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

và trong html:

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

thực sự bạn phải rất cẩn thận khi làm việc trên các bộ sưu tập phức tạp trong những tình huống như vậy (truyền xuống vài lần)


Ý tưởng tốt. Tôi không thể xác nhận nó vào lúc này. Khi tôi làm việc với vue một lần nữa, tôi sẽ kiểm tra nó.
Amio.io

1
cảm ơn bạn @ m.cichacz, đã mắc lỗi tương tự và khắc phục kịp thời nhờ đề xuất của bạn để chuyển một bản sao xuống cho đứa trẻ
không xác định

4

để ràng buộc hai chiều, bạn phải sử dụng công cụ sửa đổi .sync

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

biết thêm chi tiết ...

và bạn phải sử dụng thuộc tính đồng hồ trong thành phần con để lắng nghe và cập nhật mọi thay đổi

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

Đúng, đây là cách mới để theo dõi sự thay đổi đạo cụ trong các thành phần con.
Amio.io

2

Tôi làm việc với một tài sản được tính toán như:

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

Tài nguyên trong trường hợp này là một tài sản:

props: [ 'resources' ]

1

Đối với tôi đây là một giải pháp lịch sự để có một thay đổi prop (s) cụ thể và tạo logic với nó

Tôi sẽ sử dụng propsvà biến các computedthuộc tính để tạo logic sau khi nhận được các thay đổi

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

Vì vậy, chúng ta có thể sử dụng _objectDetail trên html render

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

hoặc trong một số phương pháp:

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

0

Bạn có thể sử dụng chế độ đồng hồ để phát hiện các thay đổi:

Làm mọi thứ ở cấp độ nguyên tử. Vì vậy, trước tiên hãy kiểm tra xem phương thức đồng hồ có được gọi hay không bằng cách an ủi một cái gì đó bên trong. Một khi nó đã được thiết lập mà đồng hồ đang được gọi, hãy phá vỡ nó bằng logic kinh doanh của bạn.

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

0

Tôi sử dụng propsvà biến các computedthuộc tính nếu tôi cần tạo logic sau để nhận các thay đổi

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

        if (someValidation)
        ...
    }
}

-1

nếu myProp là một đối tượng, nó có thể không được thay đổi thông thường. vì vậy, đồng hồ sẽ không bao giờ được kích hoạt. Lý do tại sao myProp không được thay đổi là vì bạn chỉ cần đặt một số khóa của myProp trong hầu hết các trường hợp. myProp vẫn là một. hãy thử xem các đạo cụ của myProp, như "myProp.a", nó sẽ hoạt động.


-1

Các chức năng đồng hồ nên đặt trong thành phần trẻ em. Không phải cha mẹ.


-1

@JoeSchr có một câu trả lời hay. đây là một cách khác để làm điều này nếu bạn không muốn 'sâu: đúng'.

 mounted() {
    this.yourMethod();
    // re-render any time a prop changes
    Object.keys(this.$options.props).forEach(key => {
      this.$watch(key, this.yourMethod);
    });
  },
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.