programing

Vue.js - 중첩된 데이터를 올바르게 감시하는 방법

prostudy 2022. 3. 23. 00:23
반응형

Vue.js - 중첩된 데이터를 올바르게 감시하는 방법

나는 프로펠러 변형을 제대로 관찰하는 방법을 이해하려고 노력하고 있다.상위 구성 요소(.vue 파일)를 가지고 있는데, 이 구성 요소는 ajax 호출에서 데이터를 수신하여 개체 내부에 넣은 후 v-for 지시어를 통해 일부 하위 구성 요소를 렌더링하는 데 사용하며, 이는 내 구현의 단순화 이하임.

<template>
    <div>
        <player v-for="(item, key, index) in players"
            :item="item"
            :index="index"
            :key="key"">
        </player>
    </div>
</template>

...그럼 안으로.<script>태그:

 data(){
     return {
         players: {}
 },
 created(){
        let self = this;
        this.$http.get('../serv/config/player.php').then((response) => {
            let pls = response.body;
            for (let p in pls) {
                self.$set(self.players, p, pls[p]);
            }
    });
}

항목 개체는 다음과 같다.

item:{
   prop: value,
   someOtherProp: {
       nestedProp: nestedValue,
       myArray: [{type: "a", num: 1},{type: "b" num: 6} ...]
    },
}

이제 내 아이 "플레이어" 구성 요소 내에서 Item의 재산 변동을 감시하려고 하며, 다음을 사용한다.

...
watch:{
    'item.someOtherProp'(newVal){
        //to work with changes in "myArray"
    },
    'item.prop'(newVal){
        //to work with changes in prop
    }
}

효과가 있긴 한데 좀 까다로운 것 같아서 이게 맞는 방법인지 궁금했어.내 목표는 매번 어떤 행동을 하는 것이다.prop변경 또는myArray기존 요소 내부의 새로운 요소 또는 변형을 얻는다.어떤 제안이라도 감사할 것이다.

이를 위해 심층 감시자를 사용할 수 있다.

watch: {
  item: {
     handler(val){
       // do stuff
     },
     deep: true
  }
}

이제 에서 객체에 대한 모든 변경 사항을 감지함item어레이 및 어레이 자체에 대한 추가(Vue.set과 함께 사용되는 경우)여기 JSFiddle: http://jsfiddle.net/je2rw3rs/

편집

최상위 객체의 모든 변경 사항을 감시하지 않고 중첩된 객체를 직접 보기 위한 덜 어색한 구문만 원하면 간단히 a를 시청할 수 있다.computed대신:

var vm = new Vue({
  el: '#app',
  computed: {
    foo() {
      return this.item.foo;
    }
  },
  watch: {
    foo() {
      console.log('Foo Changed!');
    }
  },
  data: {
    item: {
      foo: 'foo'
    }
  }
})

여기 JSFiddle: http://jsfiddle.net/oa07r5fw/

또 다른 좋은 접근법과 조금 더 우아한 접근법은 다음과 같다.

 watch:{
     'item.someOtherProp': function (newVal, oldVal){
         //to work with changes in someOtherProp
     },
     'item.prop': function(newVal, oldVal){
         //to work with changes in prop
     }
 }

(는 여기 코멘트에서 @peerbolte로부터 이 접근법을 배웠다)

VueJs의 아동 대상 깊이 감시

new Vue({
    el: "#myElement",
    data: {
        entity: {
            properties: []
        }
    },
    watch: {
        'entity.properties': {
            handler: function (after, before) {
                // Changes detected. Do work...     
            },
            deep: true
        }
    }
});

만약 당신이 잠시동안 부동산을 보다가 그것을 해제하고 싶다면?

또는 라이브러리 하위 구성 요소 속성을 보기 위해?

동적 감시기(dynamic watcher)를 사용할 수 있다.

this.$watch(
 'object.property', //what you want to watch
 (newVal, oldVal) => {
    //execute your code here
 }
)

$watch호출되면 보기가 중지되는 언워치 함수를 반환한다.

var unwatch = vm.$watch('a', cb)
// later, teardown the watcher
unwatch()

또한 당신은 그 제품을 사용할 수 있다.deep옵션:

this.$watch(
'someObject', () => {
    //execute your code here
},
{ deep: true }
)

문서를 확인하십시오.

개인적으로 나는 다음과 같은 청정 구현을 선호한다.

watch: {
  myVariable: {
     handler(newVal, oldVal){  // here having access to the new and old value
       // do stuff
     },
     deep: true,
     immediate: true //  Also very important the immediate in case you need it, the callback will be called immediately after the start of the observation

  }
}

내가 이 솔루션을 '해킹'하곤 했던 또 다른 방법은 다음과 같은 것이었다.분리대를 설치했다.computed중첩된 객체 값을 반환하는 값.

data : function(){
    return {
        countries : {
            UnitedStates : {
                value: "hello world";
            }.
        },
    };
},
computed : {
    helperName : function(){
        return this.countries.UnitedStates.value;
    },
},
watch : {
    helperName : function(newVal, oldVal){
        // do this...
    }
}

여기에 언급된 것을 보지 못했으며, 또한 사용 가능함.vue-property-decorator확장 중인 경우 패턴Vue계급의

import { Watch, Vue } from 'vue-property-decorator';

export default class SomeClass extends Vue {
   ...

   @Watch('item.someOtherProp')
   someOtherPropChange(newVal, oldVal) {
      // do something
   }

   ...
}

목록에서 개별 변경 항목 추적

목록의 모든 항목을 보고 목록의 어떤 항목이 변경되었는지 확인하려면 다음과 같이 모든 항목에 개별적으로 사용자 지정 감시 장치를 설정하십시오.

var vm = new Vue({
  data: {
    list: [
      {name: 'obj1 to watch'},
      {name: 'obj2 to watch'},
    ],
  },
  methods: {
    handleChange (newVal, oldVal) {
      // Handle changes here!
      // NOTE: For mutated objects, newVal and oldVal will be identical.
      console.log(newVal);
    },
  },
  created () {
    this.list.forEach((val) => {
      this.$watch(() => val, this.handleChange, {deep: true});
    });
  },
});

목록이 (처음 질문처럼) 바로 채워지지 않은 경우 로직을 밖으로 이동시킬 수 있다.created예를 들어, 내부와 같은 필요한 모든 곳에.then()막다

변경 목록 보기

목록 자체가 새 항목 또는 제거된 항목으로 업데이트되는 경우, 나는 목록 자체를 "허용"하고 목록 변경에 따라 동적으로 항목을 감시/비감시하는 유용한 패턴을 개발했다.

// NOTE: This example uses Lodash (_.differenceBy and _.pull) to compare lists
//       and remove list items. The same result could be achieved with lots of
//       list.indexOf(...) if you need to avoid external libraries.

var vm = new Vue({
  data: {
    list: [
      {name: 'obj1 to watch'},
      {name: 'obj2 to watch'},
    ],
    watchTracker: [],
  },
  methods: {
    handleChange (newVal, oldVal) {
      // Handle changes here!
      console.log(newVal);
    },
    updateWatchers () {
      // Helper function for comparing list items to the "watchTracker".
      const getItem = (val) => val.item || val;

      // Items that aren't already watched: watch and add to watched list.
      _.differenceBy(this.list, this.watchTracker, getItem).forEach((item) => {
        const unwatch = this.$watch(() => item, this.handleChange, {deep: true});
        this.watchTracker.push({ item: item, unwatch: unwatch });
        // Uncomment below if adding a new item to the list should count as a "change".
        // this.handleChange(item);
      });

      // Items that no longer exist: unwatch and remove from the watched list.
      _.differenceBy(this.watchTracker, this.list, getItem).forEach((watchObj) => {
        watchObj.unwatch();
        _.pull(this.watchTracker, watchObj);
        // Optionally add any further cleanup in here for when items are removed.
      });
    },
  },
  watch: {
    list () {
      return this.updateWatchers();
    },
  },
  created () {
    return this.updateWatchers();
  },
});

나도 이런 식으로 작동한다는 걸 알아냈어

watch: {
    "details.position"(newValue, oldValue) {
        console.log("changes here")
    }
},
data() {
    return {
      details: {
          position: ""
      }
    }
}

사용의 승인된 답변에 대한 나의 문제deep: true배열을 딥워치할 때 배열의 어떤 요소에 변경 사항이 포함되어 있는지 쉽게 식별할 수 없다는 것이다.내가 찾은 유일한 확실한 해결책은 이 대답으로, 어레이 요소를 개별적으로 볼 수 있도록 구성 요소를 만드는 방법을 설명한다.

나에게 해답은 하나도 효과가 없었다.실제로 여러 번 호출되는 구성요소를 사용하여 중첩된 데이터를 보려는 경우그래서 그들을 식별하기 위해 다른 소품으로 불려진다.예를 들면<MyComponent chart="chart1"/> <MyComponent chart="chart2"/>내 해결 방법은 마지막으로 업데이트된 속성을 가리키도록 수동으로 업데이트하는 추가 vuex 상태 변수를 생성하는 것이다.

다음은 Vuex.ts 구현 예:

export default new Vuex.Store({
    state: {
        hovEpacTduList: {},  // a json of arrays to be shared by different components, 
                             // for example  hovEpacTduList["chart1"]=[2,6,9]
        hovEpacTduListChangeForChart: "chart1"  // to watch for latest update, 
                                                // here to access "chart1" update 
   },
   mutations: {
        setHovEpacTduList: (state, payload) => {
            state.hovEpacTduListChangeForChart = payload.chart // we will watch hovEpacTduListChangeForChart
            state.hovEpacTduList[payload.chart] = payload.list // instead of hovEpacTduList, which vuex cannot watch
        },
}

저장소를 업데이트하는 모든 구성 요소 기능:

    const payload = {chart:"chart1", list: [4,6,3]}
    this.$store.commit('setHovEpacTduList', payload);

이제 모든 구성 요소에서 업데이트를 받으십시오.

    computed: {
        hovEpacTduListChangeForChart() {
            return this.$store.state.hovEpacTduListChangeForChart;
        }
    },
    watch: {
        hovEpacTduListChangeForChart(chart) {
            if (chart === this.chart)  // the component was created with chart as a prop <MyComponent chart="chart1"/> 
                console.log("Update! for", chart, this.$store.state.hovEpacTduList[chart]);
        },
    },

Vue 3를 찾는 모든 사람을 위해


import { watch } from 'vue';

...
...

watch(
  () => yourNestedObject,              // first param, your object
  (currValue, prevValue) => {          // second param, watcher callback
    console.log(currValue, prevValue);
  },
  { deep: true }                       // third param, for deep checking
);

여기에서 설명서를 참조하십시오. https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watch

나는 딥:true를 사용했지만 감시 기능에서 예전과 새로운 값이 항상 같다는 것을 알았다.이전 솔루션에 대한 대안으로, 나는 이것을 시도해 보았다. 그것은 전체 객체를 문자열로 변환하여 모든 객체의 변화를 확인할 것이다.

created() {
    this.$watch(
        () => JSON.stringify(this.object),
            (newValue, oldValue) => {
                //do your stuff                
            }
    );
},

중첩된 속성에 대한 감시자를 작성하는 방법:

    new Vue({
        ...allYourOtherStuff,
        watch: {
            ['foo.bar'](newValue, oldValue) {
                // Do stuff here
            }
        }
    });

비동기 감시자에게도 이 구문을 사용할 수 있다.

    new Vue({
        ...allYourOtherStuff,
        watch: {
            async ['foo.bar'](newValue, oldValue) {
                // Do stuff here
            }
        }
    });

참조URL: https://stackoverflow.com/questions/42133894/vue-js-how-to-properly-watch-for-nested-data

반응형