CompositionAPI; use of Setup function; Reactive, ref, computed function; lifecycle hook; Provide/Inject; watch/watchEffect; setup syntactic sugar

1_ Know Composition API

1.1 Disadvantages of _Options API

In Vue2, the way to write components is the Options API:

  • A major feature of the Options API is to write the corresponding functional modules in the corresponding properties;
  • For example, data defines data, methods are defined in methods, computed attributes are defined in computed, and watch attributes are monitored for changes, including life cycle hooks;

But this code has a big drawback:

  • When implementing a certain function, the code logic corresponding to this function will be split into each attribute;
  • When the component becomes larger and more complex, the list of logical concerns will grow, and the logic of the same function will be split;
  • Especially for those who did not write these components in the first place, the code of this component is difficult to read and understand (other people who read components);

Let's look at a very large component, where the logical functions are divided by color:

  • This fragmented code makes understanding and maintaining this complex component extremely difficult and hides potential logic problems;
  • And when dealing with a single logical concern, it is necessary to continuously jump to the corresponding code block;

It would be better if the code related to the same logical concern can be collected together. That's what the Composition API is trying to do, and what it can help accomplish. Some people also refer to Vue Composition API as VCA.


1.2_ Understanding Composition API

In order to start using the Composition API, there needs to be a place where you can actually use it (write code). In the Vue component, this position is setupthe function;

setup is another option for components:

  • It's just that this option is powerful enough to replace most of the other options written before;
  • Such as methods, computed, watch, data, life cycle, etc.;

Basic use of 2_Setup function

2.1 Parameters of the setup function

The parameters of the setup function, it mainly has two parameters:

  • The first parameter: props
  • The second parameter: context

The parameter propsis the attribute passed by the parent component, which will be placed in the props object. If it needs to be used in the setup, it can be obtained directly through the props parameter

  • Define the type in the props option;
  • Attributes in props, such as message, can still be used in the template;
  • If you want to use props in the setup function, you cannot get it through this;
  • Because props are directly passed as parameters to the setup function, they can be used directly through parameters;

Parameters context, called SetupContext, which contains three properties:

  • attrs: all non-prop attributes;
  • slots: the slot passed by the parent component;
  • emit: emit is used when an event needs to be emitted inside the component (because this.$emit cannot be used to emit an event because this.$emit cannot be accessed);

2.2 The return value of the_setup function

setup is a function, and it also has a return value. What is its use?

  • The return value of setup can be used in the template template;

  • That is, the data option can be replaced by the return value of setup;

  • It is even possible to return an execution function instead of the method defined in methods

For a defined variable, by default, Vue does not track its changes to cause responsive operations on the interface;


3_Reactive API

The data defined in setup provides responsive features, so reactive functions can be used.

const  test = reactive({
    
    
   aaa : "hhh",
   bbb : 3344
})

The general principle of reactive

  • After the data processed by the reactive function is used, dependency collection will be performed when the data is used again;
  • When the data changes, all collected dependencies perform corresponding responsive operations (such as updating the interface);
  • In fact, the written data option is also internally handed over to the reactive function to program it into a responsive object;

3.1_Vue's one-way data flow

In Vue.js, data-driven is one of its core principles, and single-item data flow is an important concept. It means that the data transfer method in the Vue component can only be passed from the parent component to the child component, and the reverse transfer is not allowed.

The role of unidirectional data flow

  • Simplified data flow: A single data flow can help to better understand the direction of data flow, avoiding the confusion and complexity of data flow.

  • Improve code maintainability: Since the data flow is unidirectional, when data changes, you only need to find the affected components, which improves code maintainability.

  • Enhanced code predictability: Because data flow is unidirectional, you can predict how data will flow, allowing you to more accurately track down issues and troubleshoot errors.

In Vue, single-item data flow is achieved by passing props parameters from parent components to child components. The parent component passes data to the child component as a props attribute, and the child component receives the data passed by the parent component through props and uses it inside the component.


3.2_readonly

A responsive object can be obtained through reactive or ref, but in some cases, the responsive object passed to other places (components) wants to be used in another place (component), but cannot be modified. At this time How to prevent this from happening?

  • The method provided by Vue3 readonly;
  • readonly will return the read-only proxy of the original object (that is, it is still a Proxy, which is a proxy whose set method is hijacked and cannot be modified);

The common readonly method in development will pass in three types of parameters:

  • Type 1: common object;
  • Type 2: the object returned by reactive;
  • Type 3: ref object;

During the use of readonly, there are the following rules:

  • The objects returned by readonly are not allowed to be modified;

  • But the original object processed by readonly is allowed to be modified;

    • For example, const info = readonly(obj), the info object is not allowed to be modified;

    • When obj is modified, the info object returned by readonly will also be modified;

    • But you cannot modify the object info returned by readonly;

When readonly passes data to other components, you want other components to use the passed content, but when they are not allowed to modify, you can use readonly;


3.3 API for Reactive judgment

isProxy: Check if the object is a proxy created by reactive or readonly.

isReactive

  • Check if the object is a reactive proxy created by reactive:
  • It will also return true if the proxy was created by readonly but wraps another proxy created by reactive;

isReadonly: Checks if the object is a read-only proxy created by readonly.

toRaw: Returns the original object for reactive or readonly proxies (keeping a persistent reference to the original object is not recommended. Use with caution).

shallowReactive: Creates a reactive proxy that tracks the responsiveness of its own property, but does not perform deep reactive transformations of nested objects (deep or native objects).

shallowReadonly: Create a proxy that makes its own property read-only, but does not perform deep read-only conversion of nested objects (deep is still readable and writable).


4_ref

The reactive API has requirements for the type of input, which must be an object or an array type. If a basic data type (String, Number, Boolean) is passed in, a warning will be reported;

So Vue3 provides another API:ref API

  • ref will return a mutable responsive object, which maintains its internal value as a responsive reference, which is the source of the ref name;
  • Its internal value is maintained in the value attribute of ref;

There are two caveats here:

  • When introducing the value of ref in the template, Vue will automatically helpunpackoperation, so it is not necessary to use ref.value in the template;
  • But inside the setup function, it is still a ref reference, so when operating on it, you still need to use the ref.value method;

4.1_toRefs

Use ES6's destructuring syntax to deconstruct the object returned by reactive to obtain the value, then whether it is to modify the variable after the structure or modify the state object returned by reactive, the data is no longer responsive:

const state = reactive({
    
    
  name = "hhh",
  age = 18
})

const {
    
     name , age} = state

So is there a way to make the deconstructed properties responsive?

  • Vue provides a toRefsfunction that can convert the attributes in the object returned by reactive into ref;
  • Then the name and age that are constructed again are both ref;
const {
    
     name,age } = toRefs(state)

This approach is equivalent to establishing a link between state.name and ref.value, and any modification will cause another change;


toRef

If you only want to convert the properties in a reactive object to ref, you can use the toRef method:

const name = toRef(state,'name')

4.2_ref Other APIs

unref

  • If you want to get the value in a ref reference, you can also use the unref method:
  • If the parameter is a ref, returns the internal value, otherwise returns the parameter itself;
  • This is a syntactic sugar function for val = isRef(val) ? val.value : val;

isRef : Determine whether the value is a ref object.

shallowRef: create a shallow ref object;

triggerRef : manually trigger the side effects associated with shallowRef


5_computed

I have learned about the computed attribute in the Options API. When some attributes depend on other states, you can use the computed attribute to handle it.

  • In the previous Options API, it is done using the computed option;
  • In the Composition API, you can use the computed method in the setup function to write a computed property;

How to use computed?

  • Method 1: Receive a getterfunction and return an unchanging ref object for the value returned by the getter function;
  • Method 2: Receive an object with getand setand return a mutable (readable and writable) ref object;
<template>
  <h2>{
    
    {
    
     fullname }}</h2>
  <button @click="setFullname">设置fullname</button>
  <h2>{
    
    {
    
     scoreLevel }}</h2>
</template>

<script>
import {
    
     reactive, computed, ref } from 'vue'

  export default {
    
    
    setup() {
    
    
      // 1.定义数据
      const names = reactive({
    
    
        firstName: "kobe",
        lastName: "bryant"
      })
      // 原始的
      // const fullname = computed(() => {
    
    
      //   return names.firstName + " " + names.lastName
      // })
      const fullname = computed({
    
    
        set: function(newValue) {
    
    
          const tempNames = newValue.split(" ")
          names.firstName = tempNames[0]
          names.lastName = tempNames[1]
        },
        get: function() {
    
    
          return names.firstName + " " + names.lastName
        }
      })

      console.log(fullname)

      function setFullname() {
    
    
        fullname.value = "coder hhh"
        console.log(names)
      }


      // 2.定义score
      const score = ref(89)
      const scoreLevel = computed(() => {
    
    
        return score.value >= 60 ? "及格": "不及格"
      })

      return {
    
    
        names,
        fullname,
        setFullname,
        scoreLevel
      }
    }
  }
</script>

ref used in 6_setup

To use ref to get elements or components in setup, you only need to define a ref object and bind it to the ref attribute of the element or component;

<template>
  <!-- 1.获取元素 -->
  <h2 ref="titleRef">我是标题</h2>
  <button ref="btnRef">按钮</button>

  <button @click="getElements">获取元素</button>
</template>

<script>
  import {
    
     ref} from 'vue'

  export default {
    
    
    setup() {
    
    
      const titleRef = ref()
      const btnRef = ref()

      function getElements() {
    
    
        console.log(titleRef.value)
      }

      return {
    
    
        titleRef,
        btnRef,
        getElements
      }
    }
  }
</script>

7_lifecycle hooks

setup can be used to replace data , methods , computed , etc. options, as well as lifecycle hooks.

The life cycle function is used in the setup, and the directly imported onXfunction registers the life cycle hook;

insert image description here


8_Use Provide/Inject

8.1_Provide

The Composition API can also replace the previous Provide and Inject options.

provide to provide data. provideEach Property is defined by the method;

Two parameters can be passed in:

  • name: the property name provided;
  • value: the attribute value provided;

8.2_Inject function

injectThe required attributes and corresponding values ​​can be injected in descendant components :

Pass in two parameters:

  • The name of the property to inject;
  • Defaults;

8.3_Responsiveness of data

In order to increase the reactivity between provide value and inject value, you can use ref and reactive when provide value.

parent component

<template>
  <div>AppContent: {
    
    {
    
     name }}</div>
  <button @click="name = 'kobe'">app btn</button>
  <show-info></show-info>
</template>

<script>
  import {
    
     provide, ref } from 'vue'
  import ShowInfo from './ShowInfo.vue'

  export default {
    
    
    components: {
    
    
      ShowInfo
    },
    setup() {
    
    
      const name = ref("hhh")

      provide("name", name)
      provide("age", 18)

      return {
    
    
        name
      }
    }
  }
</script>

Subassembly

<template>
  <div>ShowInfo: {
    
    {
    
     name }}+{
    
    {
    
     age }}+{
    
    {
    
     height }} </div>
</template>

<script>
  import {
    
     inject } from 'vue'

  export default {
    
    
    // inject的options api注入, 那么依然需要手动来解包
    // inject: ["name", "age"],
    setup() {
    
    
      const name = inject("name")
      const age = inject("age")
      const height = inject("height", 1.88)

      return {
    
    
        name,
        age,
        height
      }
    }
  }
</script>

9_watch/watchEffect

9.1_Listen to data changes

In the Options API, the watch option can be used to listen to the data changes of data or props, and perform certain operations when the data changes.

In Composition API, you can use watchEffect and watch to listen to responsive data;

  • watchEffect: A dependency for automatically collecting responsive data;
  • watch: Need to manually specify the data source to listen to;

9.2 Use of_Watch

The API of the watch is completely equivalent to the Property of the component watch option:

  • Watch needs to listen to a specific data source and execute its callback function;
  • It is lazy by default, the callback will only be executed when the source being listened to changes;

If you want to perform deep listening, you need to set deep to true, or you can pass in immediate to execute immediately;

<template>
  <button @click="message='hello message'">修改message的值</button>
</template>

<script setup>
import {
    
     ref,watch } from 'vue'

// 新值
const message = ref("hhh new message")
// 侦听
watch(message , (newValue , oldValue)=>{
    
    
  console.log(newValue,oldValue)
},{
    
    
  
  // immediate立即执行
  immediate:true,
  // deep深层侦听启动
  deep:true
})
    
  return{
    
    
        message,
        btn
    }

</script>

Listeners can also listen to multiple sources simultaneously using an array

<template>
  <button @click="message = 'hello message'">修改message的值</button>
  <button @click="btn = 'hello btn'">修改btn的值</button>
</template>

<script setup>
 import {
    
     ref, watch } from 'vue'

  // 新值
  const message = ref("hhh new message")
    const btn = ref("hello new bth")
    // 侦听单个值
    watch(message, (newValue, oldValue) => {
    
    
      console.log(newValue, oldValue)
    }, {
    
    
      // immediate立即执行
      immediate: true,
      // deep深层侦听启动
      deep: true
    })
    // 侦听多个值
    watch([message, btn], (newValue, oldValue) => {
    
    
      console.log(newValue, oldValue)
    })
    return{
    
    
      message,
      btn
    }
</script>

9.3_watchEffect

When listening to some responsive data changes, you want to perform some operations, and you can use watchEffect at this time.

A case:

  • First, the function passed in by watchEffect will be executed once immediately, and dependencies will be collected during execution;
  • Secondly, only when the dependency of the watch changes, the function passed in by watchEffect will be executed again;

watchEffect stop listening

If you want to stop listening under certain circumstances, you can get the return value function of watchEffect and call this function.

<template>
  <div>
    <h2>当前计数: {
    
    {
    
     counter }}</h2>
    <button @click="counter++">+1</button>
    <button @click="name = 'kobe'">修改name</button>
  </div>
</template>

<script>
  import {
    
     watchEffect,ref } from 'vue'

  export default {
    
    
    setup() {
    
    
      const counter = ref(0)
      const name = ref("hhh")

      // 1.watchEffect传入的函数默认会直接被执行
      // 2.在执行的过程中, 会自动的收集依赖(依赖哪些响应式的数据)
      const stopWatch = watchEffect(() => {
    
    
        console.log("-------", counter.value, name.value)

        // 判断counter.value > 10
        if (counter.value >= 10) {
    
    
          stopWatch()
        }
      })

      return {
    
    
        counter,
        name
      }
    }
  }
</script>

10_extraction hook

Take the previous counter case code as an example

<template>
  <h2>About计数: {
    
    {
    
     counter }}</h2>
  <button @click="increment">+1</button>
  <button @clcik="decrement">-1</button>
</template>

<script>
import {
    
     ref } from 'vue'

export default {
    
    
  setup() {
    
    
    const counter = ref(0)

    function increment() {
    
    
      counter.value++
    }
    function decrement() {
    
    
      counter.value--
    }
    return {
    
    
      counter,
      increment,
      decrement
    }
  }
}
</script>

Assuming that multiple pages use the logic code of the counter scrip, if the code is written once for each page, it will be repeated many times, which is very inefficient. Therefore, it is planned to extract the logic code of the script, put it into the hooks folder as a separate js file, and then introduce it into each required page.

The extraction code is as follows, file path /hooks/useCounter.js

import {
    
     ref } from 'vue'

export default function useCounter() {
    
    
  const counter = ref(0)
  function increment() {
    
    
    counter.value++
  }
  function decrement() {
    
    
    counter.value--
  }

  return {
    
    
    counter,
    increment,
    decrement
  }
}

For example, this page calls the counter logic code

<template>
  <h2>Home计数: {
    
    {
    
     counter }}</h2>
  <button @click="increment">+1</button>
  <button @click="decrement">-1</button>

</template>

<script>
  // 引入
  import useCounter from '../hooks/useCounter'

  export default {
    
    
    setup() {
    
    
      // 使用
      const {
    
     counter, increment, decrement } = useCounter()
		
      return {
    
    
        counter,
        increment,
        decrement
      }
    }
  }
</script>

11_script setup syntactic sugar

<script setup>is a compile-time syntactic sugar for using the combined API in a single-file component (SFC), and is recommended when using both SFC and the combined API.

  • Less boilerplate content, more concise code;
  • Ability to declare props and throw events using pure Typescript;
  • better runtime performance;
  • Better IDE type inference performance;

The code inside will be compiled into the content of the component setup() function:

  • This means that instead of just <script>doing it once when the component is first introduced;
  • <script setup>The code in will be executed every time a component instance is created.

11.1_Top-level bindings are exposed to templates

When used <script setup>, any declared top-level bindings (including variables, function declarations, and imports) can be used directly in the template.

Note that responsive data needs to be created through ref and reactive.

<script setup>The values ​​in the scope can also be used directly as the label name of the custom component


11.2_defineProps() 和 defineEmits() 和defineExpose()

For full type inference support when declaring props and emits options, you can use the defineProps and defineEmits APIs, which will automatically be <script setup>available in

<script setup>Components using are turned off by default . The public instance of the component obtained through the template ref or the $parent chain will not expose any <script setup>bindings declared in ;

Use the defineExpose compiler macro to explicitly specify <script setup>the property to be exposed in the component:

<template>
  <div>ShowInfo: {
    
    {
    
     name }}+{
    
    {
    
     age }}</div>
  <button @click="showInfoBtnClick">showInfoButton</button>
</template>

<script setup>

// 定义props
const props = defineProps({
    
    
  name: {
    
    
    type: String,
    default: "默认值"
  },
  age: {
    
    
    type: Number,
    default: 0
  }
})

// 绑定函数, 并且发出事件
const emits = defineEmits(["infoBtnClick"])
function showInfoBtnClick() {
    
    
  emits("infoBtnClick", "showInfo内部发生了点击")
}

// 定义foo的函数,暴露出去
function foo() {
    
    
  console.log("foo function")
}
defineExpose({
    
    
  foo
})

</script>

Guess you like

Origin blog.csdn.net/qq_54075517/article/details/132429698