Luna Tech

Tutorials For Dummies.

Vue: Watchers

2022-03-21


0. Intro

Watchers | Vue.js (vuejs.org)

The Why

Computed property 可以让我们去计算 derived values,但有时候我们需要 react to state changes,比如 mutating the DOM, or changing another piece of state based on the result of an async operation.

我们可以通过使用 options API 里面的 watch option 来触发 function,触发事件可以是 reactive property change。

Shallow vs Deep - Example 3

默认的 watch 是 shallow: callback will only trigger when the watched property has been assigned a new value - it won’t trigger on nested property changes.

如果要 watch all nested mutations, 就要用 deep watcher - 注意这个可能会影响 performance。

Deep watch requires traversing all nested properties in the watched object, and can be expensive when used on large data structures. Use it only when necessary and beware of the performance implications.

Lazy vs Eager - Example 4

Lazy (default): the callback won’t be called until the watched source has changed.

Eager: in some cases we may want the same callback logic to be run eagerly - for example, we may want to fetch some initial data, and then re-fetch the data whenever relevant state changes.

We can force a watcher’s callback to be executed immediately by declaring it using an object with a handler function and the immediate: true option.

Callback Flush Timing - Example 5

当你 mutate reactive state 的时候,可能会同时触发 Vue component updates 和 watcher callbacks created by you.

默认:user-created watcher callbacks are called before Vue component updates.

改变 timing:If you want to access the DOM in a watcher callback after Vue has updated it, you need to specify the flush: 'post' option.

this.$watch() - Example 6

我们也可以用 $watch() instance method 来 create watchers。

适用场景:

This is useful when you need to conditionally set up a watcher, or only watch something in response to user interaction. It also allows you to stop the watcher early.

停止 watcher - Example 7

用 watch option 或者 $watch() method 定义的 watcher 会自动在 component unmounted 之后 stop,所以大部分时候你不需要手动停止它。

假如你需要在 unmount 之前停止 watcher,可以使用 unwatch() function.


1. Examples

Example 1

<p>
  Ask a yes/no question:
  <input v-model="question" />
</p>
<p>{{ answer }}</p>
export default {
  data() {
    return {
      question: '',
      answer: 'Questions usually contain a question mark. ;-)'
    }
  },
  watch: {
    // whenever question changes, this function will run
    question(newQuestion, oldQuestion) {
      if (newQuestion.indexOf('?') > -1) {
        this.getAnswer()
      }
    }
  },
  methods: {
    async getAnswer() {
      this.answer = 'Thinking...'
      try {
        const res = await fetch('https://yesno.wtf/api')
        this.answer = (await res.json()).answer
      } catch (error) {
        this.answer = 'Error! Could not reach the API. ' + error
      }
    }
  }
}

Example 2

我们也可以用 dot-delimited path as the key of the watch object.

export default {
  watch: {
    // Note: only simple paths. Expressions are not supported.
    'some.nested.key'(newValue) {
      // ...
    }
  }
}

Example 3 - Deep Watcher

export default {
  watch: {
    someObject: {
      handler(newValue, oldValue) {
        // Note: `newValue` will be equal to `oldValue` here
        // on nested mutations as long as the object itself
        // hasn't been replaced.
      },
      deep: true
    }
  }
}

Example 4 - Eager Watchers

export default {
  // ...
  watch: {
    question: {
      handler(newQuestion) {
        // this will be run immediately on component creation.
      },
      // force eager callback execution
      immediate: true
    }
  }
  // ...
}

Example 5 - Callback Flush Timing

export default {
  // ...
  watch: {
    key: {
      handler() {},
      flush: 'post'
    }
  }
}

Example 6 - $watch()

export default {
  created() {
    this.$watch('question', (newQuestion) => {
      // ...
    })
  }
}

Example 7 - stop a watcher

const unwatch = this.$watch('foo', callback)

// ...when the watcher is no longer needed:
unwatch()