WatchEffect for Vue3 study notes

Recently, I was watching some new features of Vue3, and I learned some hooks programming ideas, which was very inspiring. Today I’m going to start my Vue3 study notes with a very small case called watchEffect.

Vue2 v.s. Vue3

For all beginners, the most intuitive change from Vue2 to Vue3 is the Composition API — almost all Vue2 options are now in the setup function:

+ import { onMounted, reactive, watchEffect } from 'vue'

export default {
  name: "App",

+ setup( props ) {
+ const state = reactive({ /*... * /});
+ onMounted(() => { /*... * /});
+ watchEffect(() => { /*... * /});
+ return { state };
+},

-  data: () => ({ state: /*...*/ }),
-  mounted(){ /*...*/ },
-  watch: { /*...*/ },
};
Copy the code

This is a major style shift, colloquial, from object-based programming (OOP) to functional programming (FP).

Functional programming

Beginners may not be able to tell the difference between OOP and FP. You can see the difference between the onMounted and watchEffect methods by looking at the arrow function.

The characteristic of OOP is that an object (or class) is the encapsulation of data (variable) and logic (methods). In the Vue2 era, we used to write code like this:

// vue2
export {
  data: () = > ({count: 1}),
  methods: {
    message: (prefix) = > `${prefix} The ${this.count}`,},watch: {
    count() {
      console.log( this.message('Count is')); }; }}Copy the code

The internal implementation of Vue2 is complex, but externally the programming pattern is basically this: an object calls its own data and methods — this +. Operation. So in the Vue2 era, it was common to write related data and operations in the same object. But in Vue3 setup, you almost never use this; To have a function call an object or another function — a characteristic of FP.

// Vue3
import { ref, watchEffect } from "vue";

export default {
  setup() {
    const count = ref(1);
    const message = (prefix) = > `${prefix} ${count.value}`;

    watchEffect(() = > {
      console.log(message("Count is"));
    });
    return{ count, message }; }};Copy the code

Pure functions and negative effects

I don’t want to talk too much about functional programming in this article, but since Vue3’s style has shifted to FP, we have to follow FP’s rules – functions should only do one thing, return a value. The following vue component can be treated as a function, passing in the name parameter with props and returning HTML.

<template>
  <h1>{{ name }}</h1>
</template>

<script>
  export default {
    props: {
      name: String,}};</script>
Copy the code

So what’s special about this function up here?

  1. The same input produces the same output
  2. There must be no semantically observable function side effects

This is a classic pure function.

In reality, however, a Vue component might do many other things, such as:

  • To get the data
  • Event listening or subscription
  • Changing the application state
  • Modify the DOM
  • The output log

These other changes are called side effects. In the world of FP, we can no longer simply call global plugins (this.$t, this.$router, this. ; They include side effects indirectly — through other function calls. Vue3 provides a generic side effect hook called watchEffect (as the name suggests), which is our main story today.

watchEffect

WatchEffect: watchEffect: watchEffect: watchEffect: watchEffect: watchEffect: watchEffect: watchEffect

The type definition

function watchEffect(
  effect: (onInvalidate: InvalidateCbRegistrator) => void, options? : WatchEffectOptions) :StopHandle;

interfaceWatchEffectOptions { flush? :"pre" | "post" | "sync"; onTrack? :(event: DebuggerEvent) = > void; onTrigger? :(event: DebuggerEvent) = > void;
}

interface DebuggerEvent {
  effect: ReactiveEffect;
  target: any;
  type: OperationTypes;
  key: string | symbol | undefined;
}

type InvalidateCbRegistrator = (invalidate: () => void) = > void;

type StopHandle = () = > void;
Copy the code

The first parameter

WatchEffect itself is a function, and its first argument — effect — is also a function (functions are first-class citizens and can be used anywhere). Effect, as the name suggests, is a function that contains side effects. In the following code, the side effect function is used to log the console immediately when count is accessed.

// Vue3
import { ref, watchEffect } from "vue";

export default {
  setup() {
    const count = ref(0);
    const effect = () = > console.log(count.value);
    watchEffect(effect);

    setTimeout(() = > count.value++, 1000);

    return{ count }; }};Copy the code

The code above prints 0 and 1:0 because of Vue’s reactive design. The effect function is run once during the reactive element (count) dependency collection phase. 1 is the increment from the count in setTimeout one second later.

Remove side effect (onInvalidate)

Did you notice that? WatchEffect’s first argument — the effect function — has its own argument: onInvalidate, which is also a function that clears the side effects caused by the effect. (And the onInvalidate argument is also a function, haha!)

* P.S. FP is just like that, function nested function; Beginners may be a little dizzy, just get used to it *

The timing of onInvalidate is tricky: it only applies to asynchronous functions and is only called in one of two situations:

  1. wheneffectWhen a function is called again
  2. When listeners are logged out (such as when components are uninstalled)

In this code, onInvalidate will cancel the asyncOperation when the id changes or stop listening:

import { asyncOperation } from "./asyncOperation";

const id = ref(0);

watchEffect((onInvalidate) = > {
  const token = asyncOperation(id.value);

  onInvalidate(() = > {
    // run if id has changed or watcher is stopped
    token.cancel();
  });
});
Copy the code

Return value (stop listening)

Side effects occur as components are loaded and need to be cleaned up when components are unloaded. The watchEffect return value — StopHandle is still a function — is used at this point. The following stopHandle can be called explicitly in the setup function or implicitly when the component is uninstalled.

setup() {
  const stopHandle = watchEffect(() = > {
    / *... * /
  });

  / / after
  stopHandle();
}
Copy the code

Second parameter

WatchEffect also has a second parameter called Options, of type WatchEffectOptions, which is a very complex interface. It’s rarely used, but it’s a quick mention here.

The primary purpose of the second parameter is to specify to the scheduler when to run the side effect function. For example, if you want side effects to occur before the component is updated, you can set Flush to ‘pre’ (default is’ POST ‘). WatchEffectOptions can also be used for debug: the onTrack and onTrigger options can be used to debug the behavior of a listener (only during the development phase, of course).

// fire before component updates
watchEffect(
  () = > {
    / *... * /
  },
  {
    flush: "pre".onTrigger(e) {
      debugger; }});Copy the code

Pay attention to the point

WatchEffect will be used extensively in Vue3 development, here are a few points to note:

  1. If you have multiple negative effects, instead of gluing them together, write multiple WatchEffects.

    watchEffect(() = > {
      setTimeout(() = > console.log(a.val + 1), 1000);
      setTimeout(() = > console.log(b.val + 1), 1000);
    });
    Copy the code

    These two setTimeouts are independent effects, so we don’t need to listen for both a and B, so let’s write them separately:

    watchEffect(() = > {
      setTimeout(() = > console.log(a.val + 1), 1000);
    });
    
    watchEffect(() = > {
      setTimeout(() = > console.log(b.val + 1), 1000);
    });
    Copy the code
  2. WatchEffect can also be placed within other lifecycle functions

    For example, if your side-effect function calls the DOM the first time it is executed, you can put it in an onMounted hook:

    onMounted(() = > {
      watchEffect(() = > {
        // access the DOM or template refs
      });
    }
    Copy the code

summary

WatchEffect is basically a phenomenal copy of React’s useEffect; This is not diss Vue3, but watchEffect and useEffect are both designed from a mature programming paradigm — FP. When you look at the Vue3 documentation, don’t just look at the API usage. Vue is just a tool, solving problems is the ultimate goal. We still need to focus on understanding the design idea of the framework; Realize, is really master the means to solve the problem. Finally, it ends with a famous quote from Dugu:

Epee without feng, big Qiao does not work, forty years old before holding the rampant world; After the age of 40, the sword is not stuck in things, plants, trees, bamboo and stones.

The post was synced from An-Onion’s Github. Code word is not easy, welcome to like.