Vue3 composite API

Preface

As the business complexity of traditional components increases, the amount of code will continue to increase, and the entire code logic is difficult to read and understand. Where Vue3 uses the composed API is setup. In a setup, we can group parts of code by logical concerns, then extract pieces of logic and share the code with other components. Therefore, the Composition API allows us to write more organized code.

 1. Setup component

import { ref } from 'vue';
export default {
    setup(){
        const name = ref('Composition Api');
        const showName = () => console.log(`Hello${name.value}`);
        const status = ref(false);
        const toggle = () => status.value = true;
        onMounted(() => {
            showName();
        });
        return { name,status, toggle};
    },
};
//setup() 函数在组件创建 created() 之前执行。
//setup() 函数接收两个参数 props 和 context。
//第一个参数 props,它是响应式的,当传入新的 prop 时,它将被更新。
//第二个参数 context 是一个普通的 JavaScript 对象,它是一个上下文对象,暴露了其它可能在 setup 中有用的值。

Note: You should avoid using this in setup as it will not find the component instance. The call to setup occurs before the data property, computed property or methods are parsed, so they cannot be obtained in setup.

<template>
    <div>
        <p>计数器实例: {
   
   { count }}</p>
        <input @click="myFn" type="button" value="点我加 1">
    </div>
</template>

<script>
import {ref, onMounted} from 'vue';

export default {
    setup(){
        //定义初始值为0的变量,要使用ref方法赋值,直接赋值的话变量改变不会更新 UI
        let count = ref(0);

        // 定义点击事件 myFn
        function myFn(){
            console.log(count);
            count.value += 1;
        }
       
       // 组件被挂载时,我们用 onMounted 钩子记录一些消息
        onMounted(() => console.log('component mounted!'));

        // 外部使用组合API中定义的变量或方法,在模板中可用。
        return {count,myFn} // 返回的函数与方法的行为相同
    }
}
</script>

In Vue 3.0, we can make any reactive variable work anywhere through a new ref function, as shown below:

import { ref } from 'vue'

let count = ref(0);

The ref() function can create a responsive data object based on a given value. The return value is an object and contains only one .value attribute.

Within the setup() function, the responsive data created by ref() returns an object , so it needs  to be accessed using .value  .

import { ref } from 'vue'

const counter = ref(0)

console.log(counter) // { value: 0 }
console.log(counter.value) // 0

counter.value++
console.log(counter.value) // 1

2. Vue combined API life cycle hook

In Vue2, we implement life cycle hook functions in the following ways:

export default {
  beforeMount() {
    console.log('V2 beforeMount!')
  },
  mounted() {
    console.log('V2 mounted!')
  }
};

To implement life cycle hook functions in the Vue3 composition API, you can   use the function with the on prefix in the setup() function:

import { onBeforeMount, onMounted } from 'vue';
export default {
  setup() {
    onBeforeMount(() => {
      console.log('V3 beforeMount!');
    })
    onMounted(() => {
      console.log('V3 mounted!');
    })
  }
};

The following table is the mapping between Options API and Composition API, including how to call life cycle hooks inside setup ():

Vue2 Options-based API Vue Composition API
beforeCreate setup()
created setup()
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeDestroy onBeforeUnmount
destroyed onUnmounted
errorCaptured onErrorCaptured

Because setup operates around the beforeCreate and created lifecycle hooks , there is no need to define them explicitly. In other words, any code written in these hooks should be written directly in the setup function.

These functions accept a callback function that will be executed when the hook is called by the component:

setup() {
...
    // 组件被挂载时,我们用 onMounted 钩子记录一些消息
    onMounted(() => console.log('component mounted!'));
...
}

3. Template reference

When using the composition API, the concepts of reactive references and template references are unified.

To get a reference to an element or component instance within a template, we can declare a ref and return it from setup() as usual:

<template>
  <div ref="root">This is a root element</div>
</template>

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

  export default {
    setup() {
      const root = ref(null)

      onMounted(() => {
        // DOM 元素将在初始渲染后分配给 ref
        console.log(root.value) // <div>This is a root element</div>
      })

      return {
        root
      }
    }
  }
</script>

In the above example, we expose root in the rendering context and bind it to the div as its ref via ref="root".

Refs used as templates behave like any other ref: they are reactive and can be passed into (or returned from) composite functions.

3.1 Usage in v-for

Composite API template references have no special treatment when used internally by v-for. Instead, use function references to perform custom processing:

<template>
  <div v-for="(item, i) in list" :ref="el => { if (el) divs[i] = el }">
    {
   
   { item }}
  </div>
</template>

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

  export default {
    setup() {
      const list = reactive([1, 2, 3])
      const divs = ref([])

      // 确保在每次更新之前重置ref
      onBeforeUpdate(() => {
        divs.value = []
      })

      return {
        list,
        divs
      }
    }
  }
</script>

3.2 Listening for template references

Listening for changes to template references can replace the lifecycle hooks demonstrated in the previous example.

But a key difference with lifecycle hooks is that watch() and watchEffect() have side effects when running before the DOM is mounted or updated, so when the listener runs, the template reference has not yet been updated.

<template>
  <div ref="root">This is a root element</div>
</template>

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

  export default {
    setup() {
      const root = ref(null)

      watchEffect(() => {
        // 这个副作用在 DOM 更新之前运行,因此,模板引用还没有持有对元素的引用。
        console.log(root.value) // => null
      })

      return {
        root
      }
    }
  }
</script>

Therefore, listeners that use template references should be defined with the flush: 'post' option, which will run the side effect after the DOM is updated, ensuring that the template reference is in sync with the DOM and refers to the correct element.

<template>
  <div ref="root">This is a root element</div>
</template>

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

  export default {
    setup() {
      const root = ref(null)

      watchEffect(() => {
        console.log(root.value) // => <div>This is a root element</div>
      },
      {
        flush: 'post'
      })

      return {
        root
      }
    }
  }
</script>

Guess you like

Origin blog.csdn.net/qq_40453972/article/details/131376269