Vue3’s life cycle, computed and watch, watcheffect

1. Foreword

Hello everyone, I’m __Sanwu in Diqidian, I’ve been going around for a while, and I finally have a little free time, so I can calm down and learn about vue3. Today, I will hook the function on the hour, and record it after learning to deepen my impression.

2. Life cycle

The life cycles of vue3 and vue2 are basically the same, the difference is that vue3 uses setup instead of beforeCreate and created.

And the life cycle of vue3 is loaded on demand, and on is added before the original naming basis, except for setup.

vue2 vue3
beforeCreate setup
created setup
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered

The overall life cycle can still use the idea of vue2.x, just change beforeCreate and created to setup.

image.png

The writing method is also different from vue2.x and needs to be introduced.

Fill in the setup function or setup tag, and use the setup tag below.

<script setup lang="ts">

import {<!-- --> onBeforeMount, onMounted } from 'vue'
onBeforeMount(() => {<!-- -->
  console.log('------onBeforeMount', 1)
})
onMounted(() => {<!-- -->
  console.log('------onMounted', 2)
})
</script>

3. Listener function

1, watch

Lazy monitoring, the function is the same as this.$watch provided by vue2.x.

The object monitored by vue3’s watch must be a responsive object, that is, a variable defined by reactive or ref.

Listening to a single source

const state = reactive({ count: 0 })
watch(
  () => state.count,
  (count, prevCount) => {
    /* ... */
  }
)

// listen directly to a ref
const count = ref(0)
watch(count, (count, prevCount) => {
  /* ... */
})

Multiple sources are monitored in the form of an array. After trying it, it seems that the values before monitoring were not found, and several of them are modified values.

const state = reactive({<!-- --> count: 0 })
const state2 = reactive({<!-- --> count: 3 })
watch([state, state2], ([stateNow, state2Now], [prevState, prevState2]) => {<!-- -->
  console.log('Changed value', stateNow, state2Now)
  console.log('Changed value', prevState, prevState2)
  console.log('listening object', state, state2)
})

image.png

2, watcheffect

Why do you need watcheffect when you have watch, because watch is lazy, watch listens to one or more specific responsive properties, only triggers when these dependencies change, and requires < If code>immediate is true, the monitoring will start after the component is created; and watchEffect is any dependency in the monitoring function, and the default is to start monitoring after the component is created. When the monitoring function Fires when any of the dependencies in the changes.

watcheffect focuses on the process! ! !

2.1 General use

We want to monitor the count value of the state. By the way, let’s take a look at the triggering sequence of several monitoring functions (written in the previous section).

import {<!-- --> onBeforeMount, onMounted, reactive, watch, watchEffect } from 'vue'
watchEffect(() => {<!-- -->
  console.log('order 2', 'watchEffect monitoring', state.count)
})

It can be seen that the watch monitors a single source, the trigger is the fastest, followed by watchEffect, and finally the watch monitors multiple sources.

image.png

2.2 Using asynchronous functions in watcheffect will cause side effects, how to deal with it

When using asynchronous functions in watchEffect, the following scenarios often occur:

The monitored dependency has changed, watchEffect is triggered, and then the asynchronous function is called. As a result, the asynchronous function has not been triggered yet, and the dependency has changed again. The asynchronous function is executed again. As a result, we should only need The latest one is fine, but the execution resource of an asynchronous function was wasted here.

This requires our onInvalidate parameter.

onInvalidate? Execution time:

  • When the side effect is about to be re-executed (when the listener object changes)
  • The listener is stopped (on component unmount if watchEffect is used in setup() or lifecycle hook function)

First we use the timer to create an asynchronous function change

let timer: NodeJS.Timeout|undefined
const change = async (Num: number) => {<!-- -->
  timer = await setTimeout(() => {<!-- -->
    console. log(Num)
  }, 1000)
}

Then improve our watchEffect function, add an onInvalidate, the execution timing is written on it, we can judge whether the asynchronous function is executed in the onInvalidate function, and if it is not executed, manually cancel the last timer, so that it will only execute at the end one-time timer.

watchEffect(onInvalidate => {
  console.log('order 2', 'watchEffect monitoring', state.count)
  const tmp = change(state.count)
  onInvalidate(() => {
    console.log('executed onInvalidate')
    if(timer) {
      clearTimeout(timer)
    }
  })
})

2.3 The second parameter of watchEffect-rarely used

Side effect refresh timing flush generally uses post

pre sync post
Update Timing Component Before Update Execute Forcing effects are always triggered synchronously Component After update execute

It is written as follows:

watchEffect(onInvalidate => {
  console.log('order 2', 'watchEffect monitoring', state.count)
  const tmp = change(state.count)
  console. log(tmp)
  onInvalidate(() => {
    // tmp. cancel()
    console.log('executed onInvalidate')
    if(timer) {
      clearTimeout(timer)
    }
  })
}, {
  flush: 'post',
  onTrigger () {
    console.log('trigger ontrigger')
  }
})

Even if it is a post, the trigger time of onTrigger is the first, followed by onInvalidate, and then the monitoring logic of watchEffect

image.png

2.4 How to manually stop calling

For example, after the value of our monitoring object is greater than 10, we do not intend to monitor, so we have to call it manually

Written as follows

Add logic in the change function, call stop if it is greater than 10

const change = async (Num: number) => {<!-- -->
  timer = await setTimeout(() => {<!-- -->
    console. log(Num)
    if(Num > 10) {<!-- -->
      console.log('call stop function')
      stop()
    }
  }, 1000)
}

The stop function is our watchEffect

const stop = watchEffect(onInvalidate => {
  Consistent with the content of the above function, the number of mixed characters will not be repeated
)

After the call, the watchEffect will be invalid and will no longer be monitored (when the component is destroyed, the logic is also the same, but it is called automatically)

3, computed

We are quite familiar with computed, so let’s go through it briefly.

After ref and computed are imported, we use a piece of code to talk about the triggering process.

demoCount is our calculated value. Its value is the value of the count variable + 10. At the beginning, when settimeout runs, assign a value to demoCount. This does not directly modify the value of demoCount, but triggers the set method. At this time The count = 100 – 30 = 70, and then the get method is triggered, and the result of 80 (=70 + 10) is returned.

const count = ref(0)
const demoCount = computed({
  get: () => {
    return count.value + 10
  },
  set: (param) => {
    count.value = param - 30
  }
})
setTimeout(() => {
  demoCount. value = 100
})

4. Summary

This time, I made a summary of the life cycle of vue3 and various monitoring APIs. I personally think that watch is the most used, followed by computed, and finally watchEffect. But it’s okay to know more about it.

ps: I’m __Sanwu from Diqidian, and I haven’t been in the mood lately, and I only came out with an article after going around.

Snipaste_2022-07-19_15-30-26.jpg