This is a summary of my personal notes on the Vue3 Composition API.

setup

Setup is a configuration item for a component, and the value is a function. The data, methods, computed properties, etc. used in the component are configured in the Setup.

The timing of setup is to execute once before beforeCreate. The this value is undefined.

// App.vue

<template>
  <h1>App</h1>
</template>

<script>
export default {
  name: 'App'.beforeCreate() {
    console.log('beforeCreate')},created() {
    console.log(this) // undefined
    console.log('created')},setup() {
    console.log('setup')}}</script>

// setup
// beforeCreate
// created
Copy the code

The setup function takes props and context.

Props parameters

Props is a property declared internally by a component. Props are responsive and cannot be deconstructed using ES6. Here’s an example:

// Parent component: app.vue

<template>
  <child name="Zhang" :age="20" />
</template>

<script>
import Child from './components/Child'
export default {
  name: 'App'.components: { Child }
}
</script>
Copy the code
// Child component: /components/ child.vue

<template>
  <p>The Child Child components</p>
</template>

<script>
export default {
  props: ['name'.'age'.'sex'].name: 'Child'.setup(props, context) {
    console.log(props) // Proxy {name: undefined, age: 20, sex: undefined}}}</script>
Copy the code

The context parameter

Context is a normal JavaScript object that exposes three properties of a component:

  1. attrs: passed from outside the component, but not inpropsProperties declared in the configuration.
  2. slots: Slot content received. The default name is thedefault.
  3. emit: Function that distributes custom events.
// The parent component app.vue

<template>
 <child name="Zhang" :age="20" @customClick="customClick">
   <template>
     <p>It's called the default slot</p>
   </template>
   <template #footer>
     <p>Named footer slot</p>
   </template>
 </child>
</template>

<script>
import Child from './components/Child'
export default {
 name: 'App'.components: { Child },
 setup() {
   function customClick(num) {
     console.log(Trigger customClick '- >', num) // Trigger customClick--> 666
   }
   return {
     customClick
   }
 }
}
</script>
Copy the code
// Child component: /components/ child.vue

<template>
  <p>The Child Child components</p>
</template>

<script>
export default {
  props: ['name'].name: 'Child'.setup(props, context) {
    console.log(context.attrs) // Proxy {age: 20, onCustomClick: ƒ}
    console.log(context.slots) // Proxy {footer: logon, default: logon}
    context.emit('customClick'.Awesome!) // Triggers custom events}}</script>
Copy the code

ref

Ref defines reactive data and returns an object containing reactive data. It is generally used to define a basic data type, but reference types can also be defined.

Ref if passed the base data type is still done based on the get and set of object.defineProperty (). If you pass in a reference type, you are calling the reactive function internally, which implements the object based on the Proxy.

For data wrapped by ref, the return value is an object that needs to be obtained through.value.

// App.vue<template> <! It is not required in the template.<p>{{ msg }}</p>
  <p>{{ person.name }}</p>
  <button @click="handleClick">Modify the</button>
</template>

<script>
import { ref } from 'vue'

export default {
  name: 'App'.setup() {
    // Basic data types
    const msg = ref('A message')

    // Reference type
    const person = ref({ name: 'Joe'.age: 20 })

    // Use.value to modify data
    function handleClick() {
      msg.value = 'New message'
      person.value.name = 'bill'
    }

    return {
      msg,
      person,
      handleClick
    }
  }
}
</script>

Copy the code

shallowRef

ShallowRef only handles responses of basic types, not references.

If there is an object in which subsequent functions do not modify the properties of that object, but generate new objects to replace them:

<template>
  <p>{{ msg }}</p>
  <p>{{ person.age }}</p><! -- MSG (MSG) --><input v-model="msg" /><! -- Object not listening --><input v-model.number="person.age" />
  <button @click="handleClick">Change it to a new object</button>
</template>

<script>
import { shallowRef } from 'vue'

export default {
  name: 'App'.setup() {
    const msg = shallowRef('A message')

    let person = shallowRef({
      age: 20
    })

    function handleClick() {
      // Generate new objects
      person.value = {
        age: 30}}return {
      msg,
      person,
      handleClick
    }
  }
}
</script>
Copy the code

reactive

Reactive function provides the Proxy implementation of ES6.

Define reactive functions for an object type (don’t use reactive functions for basic data types). Returns a Proxy object for a Proxy. Reactive data is deep.

// App.vue

<template>
  <p>{{ person.name }}</p>
  <p>{{ person.job.jobName }}</p>
  <button @click="handleClick">Modify the</button>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})function handleClick() {
      person.name = 'bill'
      person.job.jobName = 'Designer'
    }

    return {
      person,
      handleClick
    }
  }
}
</script>
Copy the code

shallowReactive

ShallowReactive only considers the first level of the object type.

If there is an object with a deep data structure, but only the first layer properties change:

<template>
  <p>{{ person.name }}</p>
  <p>{{ person.job.jobName }}</p>
  <input v-model="person.name" /><! -- inner attribute cannot be heard --><input v-model="person.job.jobName" />
</template>

<script>
import { shallowReactive } from 'vue'

export default {
  name: 'App'.setup() {
    const person = shallowReactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})return {
      person
    }
  }
}
</script>
Copy the code

computed

There are two methods for writing computed:

  1. Accepts a shortened form of the getter function.

  2. How objects receive get and set functions.

gettershorthand

<template>
  <p>{{ person.fullName }}</p>
</template>

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

export default {
  name: 'App'.setup() {
    const person = reactive({
      firstName: '张'.lastName: '三'
    })

    // Can be put directly into the object
    person.fullName = computed(() = > {
      return `${person.firstName}-${person.lastName}`
    })
    return {
      person
    }
  }
}
</script>
Copy the code

getandsetway

<template>
  <input type="text" v-model="person.fullName" />
</template>

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

export default {
  name: 'App'.setup() {
    const person = reactive({
      firstName: '张'.lastName: '三'
    })
    person.fullName = computed({
      get() {
        return `${person.firstName}-${person.lastName}`
      },
      set(newVal) {
        console.log(newVal)
      }
    })
    return {
      person
    }
  }
}
</script>
Copy the code

watch

The Vue3watch has the same function as the Vue2 Watch. But there are still some small details to be paid attention to. ⚠ ️

Watch takes three arguments:

  1. params: a reactive property orgetterFunction.
  2. handler: callback function.
  3. object: Is optional.
Watch (params, handler(newValue, oldValue), {immediate: true.deep: true })
Copy the code

Listen for responsive data defined by the REF

<template>
  App
</template>

<script>
import { ref, watch } from 'vue'
export default {
  name: 'App'.setup() {
  
    const msg = ref('A message')

    const person = ref({
      name: 'Joe'.age: 20
    })
    
    // Listen for basic data types defined by ref
    watch(msg, (newValue, oldValue) = > {
      console.log(NewValue ` MSG:${newValue}OldValue of MSG:${oldValue}`)})// Listen for reference types defined by ref, so use {deep: true}. Otherwise you can't listen
    watch(
      person,
      (newValue, oldValue) = > {
        // The name is the same as the name.
        console.log(The newValue ` person. Name:${newValue.name}, person oldValue. Name:${oldValue.name}`)}, {deep: true }
    )
    msg.value = 'New message' // newValue of MSG: new message, oldValue of MSG: one message
    person.value.name = 'bill' // person newvalue. name: li si, person oldValue. Name: Li si
    return { msg, person }
  }
}
</script>
Copy the code

When the reference type defined by ref is used for listening, {deep: true} must be configured. Otherwise, the listening cannot be performed.

Listen for multiple responsive data defined by the REF at the same time

You can use an array to listen for more than one response data defined by the REF at the same time.

<template>
  <input type="text" v-model="name" />
  <input type="text" v-model.number="age" />
</template>

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

export default {
  name: 'App'.setup() {
    const name = ref('Joe')
    const age = ref(20)

    // newValue and oldValue are arrays that correspond to the order of the listening variables
    watch([name, age], (newValue, oldValue) = > {
      console.log(newValue) // [newName, newAge]
      console.log(oldValue) // [oldName, oldAge]
    })

    return {
      name,
      age
    }
  }
}
</script>
Copy the code

Listen for reactive data defined by reactive

When monitoring a reactive object defined by reactive, the oldValue cannot be correctly obtained. Because listening to a responsive object or array always returns the object’s current value (newValue) and a reference to its last state value (oldValue).

<template>
  App
</template>

<script>
import { reactive, watch } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})Listening for a reactive object or array always returns a reference to the current value and the last state value of the object
    watch(person, (newValue, oldValue) = > {
      console.log(newValue === oldValue) // true
      console.log(newValue.name === oldValue.name) // true
    })

    person.name = 'bill'

    return { person }
  }
}
</script>

Copy the code

To fully listen for deeply nested objects and arrays, you need to do a deep copy of the values. This can be done by using a method such as lodash.clonedeep and returns as a getter function:

watch(
  () = > _.cloneDeep(person),
  (newValue, oldValue) = > {
    console.log(newValue === oldValue) // false
    console.log(newValue.name === oldValue.name) // false})Copy the code

Listen to a reactive object defined by reactive. There are two cases:

  1. If the first argument passed is a responsive property. The default is deep listening, and set{deep:false}Is invalid.
  2. Normal configuration if the first argument passed is a function.
<template>
  App
</template>

<script>
import { reactive, watch } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})// Pass it as an object
    watch(
      person,
      (newValue, oldValue) = > {
        console.log(newValue.job.jobName) / / designer
      },
      { deep: false } // Deep is always true, false is invalid
    )
    person.job.jobName = 'Designer'

    const book = reactive({
      bookName: 'Advanced Programming in JavaScript'.category: 'IT'.area: {
        areaName: 'Beijing'}})// Pass in the return value of the function
    watch(
      () = > book,
      (newValue, oldValue) = > {
        console.log(newValue.area.areaName) // No output
      },
      { deep: false } // The configuration is valid
    )

    book.area.areaName = 'Shanghai'

    return { person, book }
  }
}
</script>
Copy the code

If an attribute in a reactive object defined by monitoring reactive is a basic data type, the attribute is returned by a callback function.

<template>
  App
</template>

<script>
import { reactive, watch } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'.area: {
          areaName: 'Shanghai'}}})// The base data type is returned as a function, otherwise invalid
    watch(
      () = > person.name,
      (newValue, oldValue) = > {
        console.log(newValue) / / li si
      }
    )
    person.name = 'bill'

    // Reference type
    watch(
      () = > person.job,
      (newValue, oldValue) = > {
        console.log(newValue.area.areaName) / / Beijing
      },
      { deep: true }
    )

    person.job.area.areaName = 'Beijing'

    return { person }
  }
}
</script>
Copy the code

Listen for multiple reactive data defined by reactive

To monitor some properties of a reactive object defined by reactive, the listening properties are passed in through an array.

<template>
  App
</template>

<script>
import { reactive, watch } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'.area: {
          areaName: 'Shanghai'
        }
      }
    })

    watch(
      [() = > person.name, () = > person.age, () = > person.job],
      (newValue, oldValue) = > {
        console.log(newValue)
      },
      { deep: true }
    )
    person.name = 'bill'
    person.age = 30
    person.job.jobName = 'Designer'

    return { person }
  }
}
</script>
Copy the code

watchEffect

The watchEffect function does not specify which property to listen on; it listens on which property is used in the listening callback. The default initialization is performed once.

<template>
  <input type="text" v-model="person.name" />
  <input type="text" v-model="person.job.jobName" />
</template>

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

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'.area: {
          areaName: 'Shanghai'
        }
      }
    })

    watchEffect(() = > {
      console.log(person.name)
      console.log(person.job.jobName)
    })

    return { person }
  }
}
</script>
Copy the code

The life cycle

Vue3 has modified the life cycle, as shown below from the official website:

<template>
  App
</template>

<script>
import {
  onBeforeMount,
  onMounted,
  onBeforeUpdate,
  onUpdated,
  onBeforeUnmount,
  onUnmounted,
  onActivated,
  onDeactivated,
  onErrorCaptured
} from 'vue'

export default {
  beforeCreate() {
    console.log('Before Create! ')},created() {
    console.log('Create! ')},setup() {
    console.log('setup()')

    onBeforeMount(() = > {
      console.log('Before Mount! ')
    })
    onMounted(() = > {
      console.log('Mounted! ')
    })
    onBeforeUpdate(() = > {
      console.log('Before Update! ')
    })
    onUpdated(() = > {
      console.log('Updated! ')
    })
    onBeforeUnmount(() = > {
      console.log('Before Unmount! ')
    })
    onUnmounted(() = > {
      console.log('Unmounted! ')
    })
    onActivated(() = > {
      console.log('Activated! ')
    })
    onDeactivated(() = > {
      console.log('Deactivated! ')
    })
    onErrorCaptured(() = > {
      console.log('Error Captured! ')}}}</script>
Copy the code

Reference: v3.cn.vuejs.org/api/options…

ToRef and toRefs

ToRef can create a new REF for an attribute on a reactive object.

ToRefs and toRef function the same, you can create multiple toRef objects.

If objects are nested at a very deep level and are used in templates, it is necessary to use the obj. Property form, and you can use toRef and toRefs to simplify development:

<template>
  <p>{{ name }}</p>
  <p>{{ areaName }}</p>
  <p>{{ bookName }}</p>
  <input v-model="areaName" />
</template>

<script>
import { reactive, toRef, toRefs } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'.area: {
          areaName: 'Shanghai'}}})const book = reactive({
      bookName: 'Advanced Programming in JavaScript'.category: 'IT'
    })

    /* Object properties become reactive, unbunding objects to simplify the use of */
    return {
      name: toRef(person, 'name'),
      areaName: toRef(person.job.area, 'areaName'),
      ...toRefs(book)
    }
  }
}
</script>
Copy the code

ReadOnly and shallowReadOnly

  1. Readonly: Makes a reactive data read-only (deep read-only).

  2. ShallowReadOnly: Makes a reactive data read-only (shallow read-only).

You can use them if you don’t want the data to be modified:

<template>
  <div>
    <p>{{ rPerson.job.jobName }}</p>
    <! -- Not reactive and cannot be modified -->
    <input type="text" v-model="rPerson.job.jobName" />
  </div>
  <div>
    <p>{{ srPerson.job.jobName }}</p>
    <! -- Is reactive and can be modified -->
    <input type="text" v-model="srPerson.job.jobName" />
  </div>
</template>

<script>
import { reactive, readonly, shallowReadonly } from 'vue'

export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})// Cannot be modified
    const rPerson = readonly(person)

    // Only the first layer of data is considered and cannot be modified
    const srPerson = shallowReadonly(person)

    return {
      rPerson,
      srPerson
    }
  }
}
</script>
Copy the code

ToRaw and markRaw

ToRaw: Turns a reactive object generated by reactive into a regular object.

MarkRaw: Marks an object so that it will never be a responsive object again.

<template>
  App
</template>

<script>
import { reactive, toRaw, markRaw } from 'vue'
export default {
  name: 'App'.setup() {
    const person = reactive({
      name: 'Joe'.age: 20.job: {
        jobName: 'Engineer'}})const rawPerson = toRaw(person) // Return a primitive object

    person.car = markRaw({ carName: 'audi'.price: '300000' }) // Never convert to proxy

    return {
      person,
      rawPerson
    }
  }
}
</script>
Copy the code

customRef

Create a custom REF with explicit control over its dependency tracking and update triggering.

CustomRef needs to return a function that takes the track and trigger functions as parameters and should return an object with get and set.

<template>
  <input type="text" v-model="keyword" />
  <p>{{ keyword }}</p>
</template>

<script>
import { customRef } from 'vue'

export default {
  name: 'App'.setup() {
    // Custom ref, delay update by 1 second
    function myRef(value, delay = 1000) {
      return customRef((track, trigger) = > {
        return {
          get() {
            track() // Notify Vue to track value changes
            return value
          },
          set(newValue) {
            setTimeout(() = > {
              value = newValue
              trigger() // Tell Vue to rerender the template
            }, delay)
          }
        }
      })
    }
    let keyword = myRef('hello'.1000)

    return {
      keyword
    }
  }
}
</script>
Copy the code

Dojo.provide and inject

Provide and Inject implement communication between grandparent and grandchild components. The parent component has a provide option to provide the data and the child component has a Inject option to start using the data. The following picture is from the official website:

// App.vue

<template>
  App
  <child />
</template>

<script>
import { reactive, provide } from 'vue'
import Child from './components/Child'
export default {
  name: 'App'.components: { Child },
  setup() {
    const person = reactive({
      name: 'Joe'.age: 20
    })
    provide('person', person) // Pass data to the descendant component
    return {
      person
    }
  }
}
</script>
Copy the code
// components/child.vue

<template>
  <p>The child components</p>
  <son />
</template>

<script>
import son from './son'
export default {
  components: { son }
}
</script>
Copy the code
// components/son.vue

<template>
  <p>The grandson components</p>
  <p>{{ person.name }}</p>
</template>

<script>
import { inject } from 'vue'
export default {
  setup() {
    const person = inject('person') // Receive data from upper-layer components
    console.log(person) // Proxy {name: "name ", age: 20}
    return {
      person
    }
  }
}
</script>
Copy the code

Reactive data judgment

IsRef: Checks whether a value is a ref object.

IsReactive: Checks whether a reactive proxy is created by reactive.

IsReadonly: Checks whether an object is a read-only agent created by readonly.

IsProxy: Checks whether an object is a proxy created by the reactive or readonly methods.

<template>
  App
</template>

<script>
import {
  ref,
  reactive,
  readonly,
  isRef,
  isReactive,
  isReadonly,
  isProxy
} from 'vue'

export default {
  name: 'App'.setup() {
    const msg = ref('A message')

    const person = reactive({ name: 'Joe'.age: 20 })

    const readonlyPerson = readonly(person) Readonly The returned value is still a proxy object

    console.log(isRef(msg)) // true

    console.log(isReactive(person)) // true

    console.log(isReadonly(readonlyPerson)) // true

    console.log(isProxy(person)) // true

    console.log(isProxy(readonlyPerson)) // true

    return {
      msg,
      person
    }
  }
}
</script>
Copy the code

Custom instruction

In Vue3, custom directive names have been changed and some methods have been added, as follows:

  • createdCalled after the element is created, but the attributes and events have not yet taken effect.
  • beforeMount: called when the directive is first bound to an element and before the parent element is mounted.
  • mounted: called when an element is mounted to its parent element.
  • beforeUpdate: new! This is called before the component itself is updated.
  • updated: called after a component or child component has been updated.
  • beforeUnmount: called before the element is unloaded.
  • unmounted: Called only once when the instruction is unloaded.

Here’s an example:

// App.vue

<template>
  <div v-if="isShow" class="parent-title">
    <h1 v-title class="title">{{ titleMsg }}</h1>
    <p>{{ p }}</p>
  </div><! Output beforeUpdate and updated--><button @click="TitleMsg = 'new title '">Update the title</button><! Output beforeUpdate and updated--><button @click="P = 'new paragraph '">Update the paragraph</button><! BeforeUnmount, Unmounted --><button @click="isShow = false">Uninstall the component</button>
</template>

<script>
import { ref } from 'vue'
export default {
  name: 'App'.setup() {
    const titleMsg = ref('title')
    const p = ref('section')
    const isShow = ref(true)
    return {
      titleMsg,
      p,
      isShow
    }
  }
}
</script>
Copy the code
// Customize the main.js directive

const app = createApp(App)

app.directive('title', {
  created(el, binding, vnode) {
    console.log(el.className) // The value is an empty string because neither the property nor the event is in effect.
  },
  beforeMount(el, binding, vnode) {
    console.log(el.className) // The value is title and the element has been created completely.
    console.dir(el.parentNode) // The value is null because the parent node has not been inserted
  },
  mounted(el, binding, vnode) {
    console.log(el.parentNode) // The value is the parent element div. Parent-title, because the element is inserted into the parent element
  },
  beforeUpdate(el, binding, vnode) {
    console.log('beforeUpdate')},updated(el, binding, vnode) {
    console.log('update')},beforeUnmount(el, binding, vnode) {
    console.log('beforeUnmount')},unmounted(el, binding, vnode) {
    console.log('unmounted')}})Copy the code

The function is called when the same behavior is triggered when Mounted and updated:

const app = createApp(App)

app.directive('font-size'.(el, binding, vnode) = > {
  el.style.fontSize = binding.value + 'px'
})
Copy the code

Teleport components

A Teleport component is a technology that allows you to move a component’S HTML structure to a specified location.

For example, a component wants to insert it under the body element:

<template>
  App
  <teleport to="body">
    <div>Insert it under the body element as a child of the body element</div>
  </teleport>
</template>

<script>
export default {
  name: 'App'.setup(){}}</script>
Copy the code

Test the Suspense component

Suspense components can render some backup content while waiting for asynchronous components. For example, add loading animation.

The suspense> component has two slots. Nodes in the default slot are displayed as much as possible. If not, show the node in the fallback slot.

// App.vue
<template>
  <h1>App</h1>
  <Suspense>
    <template #default>
      <child />
    </template>
    <template #fallback>
      <p>Asynchronous component, loading....</p>
    </template>
  </Suspense>
</template>

<script>
// Import child from './components/child.vue' // Static import
import { defineAsyncComponent } from 'vue'
const Child = defineAsyncComponent(() = > import('./components/Child')) // Asynchronous import
export default {
  components: { Child },
  name: 'App'.setup(){}}</script>
Copy the code
// components/Child.vue

<template>
  <p>The Child Child components</p>
</template>

<script>
export default {
  name: 'Child'.setup() {
    return new Promise((resolve, reject) = > {
      setTimeout(() = > {
        resolve()
      }, 2000)}}}</script>
Copy the code

Setup () can return a Promise object when a component is introduced asynchronously.

Other adjustments

Global API

Vue3 adjusts the global API vue. XXX to the instance (app) as follows:

2. X global API 3.0 global API (app)
Vue.config app.config
Vue.config.productionTip remove
Vue.config.ignoredElements app.config.isCustomElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties

The data options

The data option should always declare a function, not an object.

Transition animation class name changed

Vue3 animation class name v-Enter changed to V-enter -form and V-leave changed to V-leave-FROM.

Vue2 writing:

/* The starting point of entry */
.v-enter {}
/* The process of entry */
.v-enter-active {}
/* End of entry */
.v-enter-to {}
/* The starting point of departure */
.v-leave {}
/* The process of leaving */
.v-leave-active {}
/* The end of leaving */
.v-leave-to {}
Copy the code

Vue3 writing:

/* The starting point of entry */
.v-enter-from {}
/* The process of entry */
.v-enter-active {}
/* End of entry */
.v-enter-to {}
/* The starting point of departure */
.v-leave-from {}
/* The process of leaving */
.v-leave-active {}
/* The end of leaving */
.v-leave-to {}
Copy the code

Vue3 remove item

  • Removed keycode as a modifier for V-ON, and config.keyCodes are no longer supported.

  • Filter filter has been deleted and is no longer supported. The official documentation suggests replacing them with method calls or computed properties.

  • Remove the v-on. Native modifier.

// The parent component defines the event
<template>
  <h1>App</h1>
  <child @close="handleClose" />
</template>

// The child component declares custom events
<script>
export default {
  name: 'Child'.emits: ['close']}</script>
Copy the code

Here are the more important points, also need to see the official document in detail: v3.cn.vuejs.org/guide/migra…

Combined function

The setup function can extract the code of each function into a separate JS file, which is more convenient to reuse. Mixin similar to Vue2.

// hooks/usePoint.js 

import { reactive, onMounted, onBeforeUnmount } from 'vue'

// Click the page to get the mouse position function
export default function() {
  const point = reactive({
    x: 0.y: 0
  })
  function clickHandle({ pageX, pageY }) {
    point.x = pageX
    point.y = pageY
  }
  onMounted(() = > {
    window.addEventListener('click', clickHandle)
  })

  onBeforeUnmount(() = > {
    window.removeEventListener('click', clickHandle)
  })
  return point
}
Copy the code
// App.vue<template> App <h2> my mouse position is X:{{point. X}},Y:{{ point.y }}</h2>
</template>

<script>
import usePoint from './hooks/usePoint'
export default {
  name: 'App'.setup() {
    / / introduce usePoint
    const point = usePoint()
    return { point }
  }
}
</script>
Copy the code

reference

V3.cn.vuejs.org/guide/compo…

zhuanlan.zhihu.com/p/68477600

www.bilibili.com/video/BV1Zy…