The magical effect of Vue3's watchEffect, the difference from watch

foreword

In Vue3, the Composition API was introduced, the watchEffect()function of which is a very powerful and flexible tool for handling changes in responsive data, making the project more elastic and flexible. It is watchdifferent from and, this article will introduce watchEffect()the definition, characteristics, watchdifference between and and precautions when using.

1. Definition

watchEffect()Functions are used to create a reactive side effect that automatically tracks dependencies. It will be executed immediately when it is initialized , and automatically track all reactive data used in the callback function, and re-run the callback function when the data changes.

For example,  todoId to use a listener to load a remote resource whenever the reference changes, if you use a watch, it is written like this:

<template>
  <div>Test</div>
</template>

<script setup>
  import { ref, watch } from 'vue'
  const todoId = ref(1)
  const data = ref(null)

  watch(
    todoId,
    async () => {
      const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)
      data.value = await response.json()
      console.log(data.value)
    },
    { immediate: true }
  )
</script>

Print:

But watchEffect()it can be simplified to:

<template>
  <div>Test</div>
</template>

<script setup>
  import { ref, watchEffect } from 'vue'
  const todoId = ref(1)
  const data = ref(null)

  watchEffect(async () => {
    const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${todoId.value}`)
    data.value = await response.json()
    console.log(data.value)
  })
</script>

 Print:

Both print data immediately. But in the following example, the callback will be executed immediately without specifying  immediate: true. During execution, it is automatically tracked  todoId.value as a dependency (similar to computed properties). Whenever  todoId.value there is a change, the callback is executed again. With that  watchEffect(), we no longer need to explicitly pass  todoId as source value.

From this point of view, watchEffect()the effect is similar to that in Vue2, computed,that is, when the dependencies change, they also change. But computedunlike with , watchEffect()there is no return value, but the callback function is executed directly.

2. Features

watchEffect()automatically tracks all reactive data used in its callbacks and re-runs the callbacks when those data changes. This makes it unnecessary for us to manually specify the specific properties to be monitored , reducing the redundancy of the code.

    For this example with only one dependency, watchEffect() the benefit is relatively small. But for listeners with multiple dependencies, using  watchEffect() can remove the burden of manually maintaining the dependency list.

    Also, if you need to listen to several properties in a nested data structure, watchEffect() it may be more efficient than a deep listener, because it will only track the properties used in the callback, rather than recursively tracking all properties. 

Example of multiple dependencies:

<template>
  <div>Test</div>
</template>

<script setup>
  import { reactive } from 'vue'
  const state = reactive({
    count: 0,
    name: 'John',
    age: 25
  })

  // 使用watchEffect()监听count和name的变化
  watchEffect(() => {
    console.log('count or name changed:', state.count, state.name)
  })

  // 模拟count和name变化
  setTimeout(() => {
    state.count = 1 // 输出'count or name changed: 1 John'
    state.name = 'Alice' // 输出'count or name changed: 1 Alice'
  }, 1000)
</script>

Print:

Examples of deep dependencies:

<template>
  <div>Test</div>
</template>

<script setup>
  import { reactive, watchEffect } from 'vue'
  const state = reactive({
    person: {
      name: 'John',
      age: 25
    },
    todos: [
      { text: 'Task 1', completed: false },
      { text: 'Task 2', completed: true },
      { text: 'Task 3', completed: false }
    ]
  })

  // 使用watchEffect()监听person对象中name和age的变化
  watchEffect(() => {
    console.log('person changed:', state.person.name, state.person.age)
  })

  // 模拟person中name和age的变化
  setTimeout(() => {
    state.person.name = 'Alice' // 输出'person changed: Alice 25'
    state.person.age = 30 // 输出'person changed: Alice 30'
  }, 1000)
</script>

Print:

3. The difference with watch

1. The monitoring method is different : watchEffect()it automatically tracks all the responsive data used, but watchneeds to manually specify the specific attributes to be monitored.

2. The monitoring granularity is different : watchEffect()what is monitored is the entire change of the responsive data, but watchthe change of the specified attribute or expression can be monitored.

3. Computed properties are handled differently : For calculated properties, watchEffect()it will automatically depend on the responsive data used by the calculated property, but watchyou need to manually specify the calculated property as the monitoring target.

4. Matters needing attention

1. Avoid excessive monitoring : Since watchEffect()all responsive data used will be tracked, it is necessary to ensure that only necessary responsive data is used in the callback function to avoid unnecessary rendering overhead.

2. Asynchronous operations need to be handled carefully : Since watchEffect()the callback function will be executed immediately, if asynchronous operations are performed in the callback function, it needs to be handled carefully to avoid unexpected behavior or side effects.

<script setup>
import { watchEffect } from 'vue'

// 它会自动停止
watchEffect(() => {})

// ...这个则不会!
setTimeout(() => {
  watchEffect(() => {})
}, 100)
</script>

3. Avoid infinite loops : When watchEffect()modifying responsive data in callbacks, it may cause infinite loops. To avoid this problem, use watch()functions and set immediate: trueoptions, or use refto store temporary data.

Guess you like

Origin blog.csdn.net/weixin_42373175/article/details/131780643