为什么我需要单击两次按钮才能在组件上设置道具?

时间:2018-09-18 21:44:20

标签: javascript vuejs2

为什么direction道具仅在第一次单击/执行后才更新,而questionid则不更新?

#vuejs @ freenode中的建议是:

  

deadbeat:我的猜测是反应性属性仅在   直接调用$ refs投票,但会在第一次更新

Vue.component('vote-component', {
  template: '<div>{{this.direction}}</div>',
  props: {
    questionid: Number,
    direction: String
  },
  methods: {
    vote() {
      console.log({
        id: this.questionid,
        direction: this.direction
      });
    }
  }
})

new Vue({
  el: "#app",
  data() {
    return {
      direction: '',
      question: {
        id: 10
      }
    }
  },
  methods: {
    vote(direction) {
      this.direction = direction;
      this.$refs.voteComp.vote();
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
  <button @click="vote('UP')">Y</button>
  <vote-component ref="voteComp" :direction="direction" :questionid="question.id" />
</div>

1 个答案:

答案 0 :(得分:0)

检查the scheduler for Vue watcher,在当前任务处触发type = String的props ='direction'的重新激活。但是direction的值将在下一个渲染周期更新(实际上是下一个event loop,您可以观看this video以便更好地理解)(Vue调用nextTick(vueQueue),与setTimeout(()=>{this.direction=newValue}, 0)

下面是一个演示:

您会看到我在App.vote添加了一个Promise。 the callback of Promise.thenmicro task,将在下一个渲染周期之前的当前任务完成后立即执行。

然后您将看到console.log('watch', newVal, oldVal)将在Promise之后执行。

我还在this.direction=direction之前放置了一个setTimeout,您会看到它将在this.$refs.voteComp.vote()之后但在console.log('watch', newVal, oldVal)之前执行,因为它是the event loop -> task queue中的较旧任务。 / p>

对于prop=questionid,它是相同的。

Vue.component('vote-component', {
  template: '<div>{{questionid}}: {{this.direction}}</div>',
  props: {
    questionid: Number,
    direction: String
  },
  watch: {
    direction: function (newVal, oldVal) {
      console.log('**watch**', newVal, oldVal)
    }
  },
  methods: {
    vote() {
      console.log({
        id: this.questionid,
        direction: this.direction
      });
    }
  }
})

new Vue({
  el: "#app",
  data() {
    return {
      direction: '',
      question: {
        id: 10
      }
    }
  },
  methods: {
    vote(direction) {
      setTimeout(()=>{
        console.log('the handler at setTimeout Executed')
      }, 0)
      this.direction = direction
      this.question.id = 7
      new Promise((resolve, reject) => {
        console.log('update direction in root')
        resolve()
      }).then(()=>{
        console.log('micro task executed')
      })
      
      this.$refs.voteComp.vote();
    }
  }
})
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
  <button @click="vote('UP')">Y</button>
  <vote-component ref="voteComp" :direction="direction" :questionid="question.id" />
</div>