In-depth understanding of hooks in Vue3 and why hooks should be used

A prerequisite knowledge

1.1 What is vue2 mixin?

Mixin, translated as mixin, does not only exist in the Vue framework, but to be precise, mixin is a kind of idea, a kind of mixing idea. The mixed content can be used where it is mixed, and it will automatically and accurately distribute the mixed content to the specified components. In Vue, mixin is equivalent to specifying the mixed variables & functions to be placed where they should be placed when they are not mixed. It can be considered that the mixin in Vue is equivalent to the component in the component.

For example : now the logic that needs to be processed in the watch in component A is hanldleParams, and the watch in component B also needs the same logic - hanldleParams. So how should we abstract and reuse these two pieces of the same logic?

Then there are two methods: ( The difference between these two methods represents the difference between mixin and utils )
1. Extract function: The first method is to extract hanldleParams in the form of a function, and then call hanldleParams in watch;
2. Mixin: Although the previous function extraction method can solve certain reuse problems, we still need to write watch in the component. After all, both components are called in the watch hook. If each component writes watch, then watch is also a duplicate, so mixin is a component that can extract watch hooks. In other words, mixin extracts not only pure functional logic, but also hooks unique to vue components. The logic can also be extracted for further reuse. This is the role of mixin. Then components A\B share a watch through mixin and can be imported. The developer does not need to place it in a specified location.
Features: The data and methods in Mixin are independent, and components do not affect each other after use.

1.2 What problems does mixin solve?

Mixins solve two types of reuse:

  1. Reuse of logic functions
  2. Vue component configuration reuse

Note: Component configuration reuse refers to the optional API in the component (for example: data, computed, watch) or the component's life cycle hook (created, mounted, destroyed)

1.3 Usage & usage scenarios?

Key: In Vue, mixin defines an object. The Vue component placed in the object has the corresponding optional API and the corresponding life cycle hook

export const mixins = {
  data() {
    return {};
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {},
};

Remember: mixins generally contain option APIs and component lifecycle hooks in vue components, because the abstraction of functions must also be placed in specific APIs or hooks in the components, so the mixin takes this into consideration and configures everything directly. API, just place it in the function. Except for the template in the component that cannot be extracted from the mixin, any other options-API can be extracted and placed in the mixin (all logic in vue2 is nothing more than placed in data, methods, computed, and watch. These can be left intact. (Actually placed in the mixin)
For example: to abstract a hanldleParams function, we usually export it in the config file, and then introduce it into the component. The method in the data is used to process the data, and the variable b in the data must be set, then this paragraph The logic can be extracted and placed in the mixin. Data or logic related to component business is generally written in the component.

For example:

// 定义一个mixin
export const mixins = {
  data() {
    return {
      msg: "我是小猪课堂",
    };
  },
  computed: {},
  created() {
    console.log("我是mixin中的created生命周期函数");
  },
  mounted() {
    console.log("我是mixin中的mounted生命周期函数");
  },
  methods: {
    clickMe() {
      console.log("我是mixin中的点击事件");
    },
  },
};
//

// src/App.vue中使用导出的mixin
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <button @click="clickMe">点击我</button>
  </div>
</template>

<script>
import { mixins } from "./mixin/index";
export default {
  name: "App",
  mixins: [mixins], // 注册mixin,这样mixin中所有的钩子函数等同于组件中钩子
  components: {},
  created(){
    console.log("组件调用minxi数据",this.msg);
  },
  mounted(){
    console.log("我是组件的mounted生命周期函数")
  }
};
</script>

The above code is equivalent to:

// src/App.vue中使用导出的mixin
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <button @click="clickMe">点击我</button>
  </div>
</template>

<script>
import { mixins } from "./mixin/index";
export default {
  name: "App",
  mixins: [mixins], // 注册mixin,这样mixin中所有的钩子函数等同于组件中钩子
  data() {
    return {
      msg: "我是小猪课堂",
    };
  },
  // 原来的组件中没有methdos方法,mixin中的方法直接放入组件中
  // 注意:vue中当发生methods函数名和mixin中的methods方法冲突时,解决方案是本组件中优先级高于mixin
  methods: {
    clickMe() {
      console.log("我是mixin中的点击事件");
    },
  },
  created(){
    console.log("我是mixin中的created生命周期函数"); 
    // mixin中的created钩子中的,生命周期中mixin的钩子优先级要高于组件中的优先级
    console.log("组件调用minxi数据",this.msg);
  },
  mounted(){
    // mixin中的 mounted 钩子中的,生命周期中mixin的钩子优先级要高于组件中的优先级
    console.log("我是mixin中的mounted生命周期函数");
    console.log("我是组件的mounted生命周期函数")
  }
};
</script>

Note: The priority of the hooks in the mixin and the vue component are the same:

  • The life cycle functions in the mixin will be executed together with the component's life cycle functions.
  • The data in the mixin can also be used in components.
  • Methods in the mixin can be called directly inside the component.
  • The execution order of life cycle functions after merging: execute the mixin first, then execute the component.

In addition, when mixin imports different components, the data will not affect each other, for example:

// mixin文件
export const mixins = {
  data() {
    return {
      msg: "我是小猪课堂",
    };
  },
  computed: {},
  created() {
    console.log("我是mixin中的created生命周期函数");
  },
  mounted() {
    console.log("我是mixin中的mounted生命周期函数");
  },
  methods: {
    clickMe() {
      console.log("我是mixin中的点击事件");
    },
  }

Use mixin in the file app and use the changeMsg function to change the msg variable of data in the mixin. At this time, the msg variable used by other components remains unchanged.

<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <button @click="clickMe">点击我</button>
    <button @click="changeMsg">更改mixin数据</button>
    <demo></demo>
  </div>
</template>

<script>
import { mixins } from "./mixin/index";
import demo from "./components/demo.vue";
export default {
  name: "App",
  mixins: [mixins],
  components: { demo },
  created() {
    console.log("组件调用minxi数据", this.msg);
  },
  mounted() {
    console.log("我是组件的mounted生命周期函数");
  },
  methods: {
    changeMsg() {
      this.msg = "我是变异的小猪课堂";
      console.log("更改后的msg:", this.msg);
    },
  },
};
</script>

1.4 What are the disadvantages?

Advantages of mixin
: Registration reuse of hook functions in components
Disadvantages:
Function names registered in the same hook with the same name will conflict (the solution to conflicts in Vue is that the priority of this component is higher than that of mixin) It takes time to locate errors, and
abuse
will cause maintenance question

2. Hooks in vue3

2.1 What are hooks

Generally speaking, during our development, we will automatically abstract logical functions and place them in utils. The pure logic placed in utils does not include anything that belongs to components, such as pure functions defined in methods, etc. And hooks is to include a layer of component-level things (hook functions, etc.) on the basis of utils. For example: every time we click the button, a pop-up window will pop up and automatically display the current date. But I put the function in util. Every time it is reused, I need to put the click=handleClick function into the date function and manage the utils through the handleClick function. Then I might as well encapsulate handleClick directly and call it directly next time, reusing the methods registration. The difference between hooks and utils: If hooks involve API data such as ref, reactive, and computed, then these data are responsive, while utils only extract public methods and are not responsive, so hooks can be understood Common method for joining vue3 api

2.2 Why do hooks appear?

So hooks are equivalent to component-level logical encapsulation. This kind of logical encapsulation can also be implemented in the mixin in vue2. Why use hooks? The difference between hooks and mixins.
Mixin is the embodiment of options API, and one is the embodiment of composition API.

1. mixin

  • There is a thing in vue2: Mixins that can achieve this function
  • Mixins are to extract these multiple identical logics. Each component only needs to introduce mixins to achieve code reuse.
  • Disadvantage 1: Will involve coverage issues
  • The data, methods, and filters of the component will overwrite the data, methods, and filters of the same name in the mixins.
  • Disadvantage 2: Implicit transfer, unclear source of variables, not conducive to reading, making the code difficult to maintain
  • Disadvantage 3: Mixin cannot pass in flexible input parameters, for example (Example 1 of Disadvantage 3):

I need to set each variable name, but the initial value of name is random, so when name is defined in mixin, its initialization must be fixed. If we want to change it, we can only register a method in method to modify name. value:

Example 1: Example of using mixin

// 混入文件:name-mixin.js
export default {
  data() {
    return {
      name: 'zhng'
    }
  },
  methods: {
    setName(name) {
      this.name = name
    }
  }
}

// 组件:my-component.vue
<template>
  <div>{
   
   { name }}</div>
<template>
<script>
import nameMixin from './name-mixin';
export default {
  mixins: [nameMixin],
  mounted() {
    setTimeout(() => {
      this.setName('Tom') // 通过在组件中调用setName传入参数值,无法传入参数,限制了Mixin的灵活性
    }, 3000)
  }
}
<script>

Example 2: Example of using hooks

import { computed, ref, Ref } from "vue"
// 定义hook方法
type CountResultProps = {
    count:Ref<number>;
    multiple:Ref<number>;
    increase:(delta?:number)=>void;
    decrease:(delta?:number)=> void;
}
export default function useCount(initValue = 1):CountResultProps{
    const count = ref(initValue)
    const increase = (delta?:number):void =>{
        if(typeof delta !== 'undefined'){
            count.value += delta
        }else{
            count.value += 1
        }
    }
    const multiple  = computed(()=>count.value * 2)
    const decrease = (delta?:number):void=>{
        if(typeof delta !== "undefined"){
            count.value -= delta
        }else{
            count.value -= 1
        }
    }
    return {
        count,
        increase,
        decrease,
        multiple
    }
 
}

// 在组件中的使用
<template>
   <p>count:{
   
   {count}}</p>
   <p>倍数:{
   
   {multiple}}</p>
   <div>
     <button @click="increase(10)">加一</button>
     <button @click="decrease(10)">减一</button> // 在模版中直接使用hooks中的方法作为回调函数
   </div>
</template>
<script setup lang="ts">
import useCount from "../views/Hook"
const {count,multiple,increase,decrease}  = useCount(10)
</script>
<style>
 
</style>

Example 3: Key examples for getting started with hooks

Key examples for getting started with hooks: Hooks files generally contain a function. For example: I need hooks to export a public name variable and setName function.

import {ref} from 'vue'
// 导出1个 name_hooks.ts文件
// hooks中不用写在setup中
export const name_hooks = function(value: string) {
   const name = ref('')
   const setName = (value: string) => {
       name.value = value
   }
   return {
      name, setName
   }
}
// 引入hooks文件
<template>
    <div>{
   
   { name }}</div>
    <select @change="setName"></select> // 这里select组件的change事件会自动传value值
    // 然后value值作为传参传递给setName
</template>
import { name_hooks } from './name_hooks'
export default defineComponent({
    setup() {
       const { name, setName } = name_hooks() // 注意: 通常需要通过解构赋值将需要的属性方法添加进组件中
       return {
          name, setName
       }
    }
})

How to use the above hooks, common operations:
1. The exported hooks is a function, and you can use ref and reactive in the function, so that the variables and methods defined by the hooks are the same as in the components.
2. The hooks function usually returns an object, and the object is For two-way bound variables, the first thing to do when they are referenced in Vue is destructuring (destructuring in vue3 requires attention and it is best to review it)
export

2.hooks:

  • In Vue3 we can: Customize Hook
  • The hook function of Vue3 is equivalent to the mixin of vue2, but: hooks are functions
  • Vue3's hook function can help us improve code reusability, allowing us to use hooks functions in different components

2.3 Hooks usage scenarios-custom hooks

2.3.1 Common business usage scenarios in hooks

In addition to some unnecessary duplication of components that reinvent the wheel, there are some functional components that really need to be encapsulated. For example, some buttons that require a back-end dictionary to be displayed on the front-end and a button that displays the loading status after clicking. Forms with query conditions, these very common business scenarios, can be encapsulated into components, but encapsulating them into components will encounter the problems mentioned above. Everyone's usage habits and encapsulation habits are different, so it is difficult for everyone to Everyone is satisfied. This scenario can be solved by hook.
(1) Encapsulate a pop-up window, reference: juejin.cn/post/695509…

Extracurricular knowledge point 1: The difference between watch and watchEffect:

image.png

Extracurricular knowledge point 2: Brief analysis of the benefits of using provide and inject:

1 Usage scenarios of provide & inject Usage
tips: There is such a tip on the Vue official website: provide and inject injection are generally suitable for use in high-order plug-ins and component libraries, and are not recommended for use in general program code usage scenarios: cross-level
components Generally speaking, communication
between our parent and child components can be used through prop and emit. If it is used across levels or multiple component nodes, we can use it through vuex. However, if we do not want to introduce vuex to achieve cross-level, we can use it at this time. Using provide and inject as a communication alternative for grandchild components

2. How to use and need points of provide &inject in vue2

Note 1 : Provide syntax
There are two syntaxes for provide: one is to assign an object, and the other is to define a function that returns an object. The
syntax for inject is usually a string number, or it can be an object.

image.png

Note 2 : Responsiveness problem: The variables injected by provide and inject are not responsive. If there are responsive requirements, they need to be implemented through reference objects. For example: the variables provided by provide to the grandchild component in the figure below are simple types, then in After the responsive transformation is performed in the grandpa component, the variable test received by the grandson component will not be transformed accordingly, because the passed in is a simple string type.

image.png

And if the provide provided by the grandfather component is a reference, and the value of an attribute within the reference type is transformed, then because the grandchild component accepts the object address, it will change accordingly, thereby achieving the effect of responsive transformation.

image.png

Summary: Provide and inject in vue2 mainly consist of two parts: using syntax and responsive data issues accepted by inject.

Extracurricular knowledge point 3: How to use provide and inject in vue3:
How should we use provide and inject in setup in vue3?

Difference : The use of provide and inject in vue3 is different from that in
vue2. Provide in vue2 is equivalent to an attribute parallel to data. The attribute value can be an object or a function that returns an object. It can be seen that provide and inject in vue2 are still process-oriented or object-oriented. It may not be obvious in inject, because inject: ['name'] accepts an array or object inject: {name}, but in provide it is provide : {name: '123'} or provide() {return {name: 123}}, the following provide and inject:

image.png

image.png

However, functional programming is used in vue3, so provide&inject are provided in functional form, and we only need to pass in parameters.

Use in vue3

Provide the provide('name', 'jack') function: the grandpa component passes provide('name', 'jack') , where the first parameter is the key to be taken by the grandson component, and the second parameter is the value.
Provide inject('name', 'Default value: Unnamed'): The grandson component obtains the provide value of the grandpa component by calling the inject function, where the first parameter is the key, and the second parameter is the default value (optional) References :blog.csdn.net/weixin_5739…

2.3.2 Specifications that custom hooks need to meet

image.png

 2.3.3 Examples of using custom hooks

hooks-1 customization: useCut

import {ref,watch} from "vue"
export function useCut({num1,num2}){
   const cutNum = ref(0);
   watch([num1,num2],(num1,num2)=>{
    cutFunc(num1,num2)
  })
  const cutFunc = (num1,num2)=>{
    cutNum.value = num1+num2
  }
  return {
    cutNum,
    cutFunc
  }
}

hooks-2 customization

import {ref,watch} from "vue"
const useAdd = ({num1,num2})=>{
  const addNum = ref(0);
  watch([num1,num2],(num1,num2)=>{
    addFunc(num1,num2)
  })
  const addFunc = (num1,num2)=>{
    addNum.value = num1+num2
  }
  return {
    addNum,
    addFunc
  }
}
export default useAdd

Use custom hooks in components

<template>
    <div>
        num1:<input v-model.number="num1" style="width:100px" />
        <br />
        num2:<input v-model.number="num2" style="width:100px" />
    </div>
    <span>加法等于:{
   
   { addNum }}</span>
    <br />
    <span>减法等于:{
   
   { cutNum }}</span>
</template>
import { ref } from 'vue'
import useAdd from './addHook.js'     //引入自动hook 
import { useCut } from './cutHook.js' //引入自动hook 
const num1 = ref(2)
const num2 = ref(1)
const { addNum, addFunc } = useAdd({ num1, num2 })  // 加法功能-自定义Hook(将响应式变量或者方法形式暴露出来)
// 因为hooks是函数,不像mixin是对象形式,所以更方便的传入组件中的data变量,交给抽象逻辑使用
addFn(num1.value, num2.value)
const { cutNum, cutFunc } = useCut({ num1, num2 }) // 减法功能-自定义Hook (将响应式变量或者方法形式暴露出来)
subFn(num1.value, num2.value)

2.3.4 Understanding hooks

Reference: juejin.cn/post/689328…

Guess you like

Origin blog.csdn.net/yu1431/article/details/132428556