Vue3 Composition API Tips (1)
Problems with Ref and Reactive usage scenarios
Ref
import { ref } from 'vue'
let foo = 0
let bar = ref(0)
foo = 1
bar = 1 // ts-error
Copy the code
Features:
- Display calls, so it is obvious which values are processed by ref for reactive updates; Also, in the demo above, TS does type checking and reports an error,
bar.value = 1
This is the correct posture. Isn’t it a bit like the.current from React? - It has fewer limitations than Reactive, which we’ll talk about reactive next
- Value is used to get the value of the reactive update
Reactive
import { reactive } from 'vue'
const foo = { prop: 0 }
const bar = reactive({ prop: 0})
foo.prop = 1
bar.prop = 1
Copy the code
The characteristics of
- Automatic unRef (.value not required)
- It is no different in type from ordinary objects
- Using ES6 object deconstruction causes the responsiveness to be lost
- Need to use the arrow function wrapper to use
watch
? AnthonyFu has not expanded on this point, not quite understand what it means
In summary, use ref whenever possible.
Ref Automatically unpacks
-
Watch accepts Ref directly as a listener and returns the unpacked value in the callback function
const counter = ref(0) watch(counter, count= > { console.log(count) // same as count.value }) Copy the code
-
Ref unpacks automatically in the template
<template> <button @click="counter ++"> count is {{counter}} <button> <template> Copy the code
-
Unpack nested Refs using Reactive
import { reactive, ref } from 'vue' const foo = ref('bar') const data = reactive({ foo, id: 10 }) data.foo // 'bar' Copy the code
unref
Unref is the inverse of ref
- If a ref is passed, return its value (.value)
- Otherwise, return the original value
Accept Ref as a function argument
Pure functions:
function add(a: number, b: number) {
return a + b
}
const a = 1
const b = 2
const c = add(a, b) / / 3
Copy the code
Take Ref as an argument and return a response:
function add(a: Ref<number>, b: Ref: <number>) {
return computed(() = > a.value + b.value)
}
const a = ref(1)
const b = ref(2)
const c = add(a, b)
c.value // 3, which implements that c.value is a reactive value
Copy the code
MayBeRef
type MayBeRef<T> = Ref<T> | T
MayBeRef supports reactive parameters
export function useTimeAgo (
time: Date | number | string | Ref<Date | number | string>
) {
return computed(() = > someFormating(unref(time)))
}
Copy the code
import { computed, unref, ref } from 'vue'
export function useTimeAgo (
time: MayBeRef<Date | number | string>
) {
return computed(() = > someFormating(unref(time)))
}
Copy the code
MayBeRef enables compatibility with reactive parameters
useTitle
import { useTitle } from '@vueuse/core'
const title = useTitle() // useTitle builds a new ref inside
title.value = 'hello wolrd' // document.title = 'hello world'
Copy the code
import { ref, computed } from 'vue'
import { useTitle } from '@vueuse/core'
const name = ref('hello')
const title = computed(() = > {
return `${name.value}, world`
})
useTitle(title) // Pass a ref, document.title = 'hello world'
name.value = 'hi' // document.title = 'hi world'
Copy the code
The realization of the useTitle
import { ref, watch } from 'vue'
import { MayBeRef } from '@vueuse/core'
export function useTitle (
newTitle: MayBeRef<string, null.undefined>
) {
const title = ref(newTitle || document.title) // If newTitle is passed, the ref will not be reref
watch(title, t= > {
if(t ! =null) {
document.title = t
}
}, { immediate: true })
return title
}
Copy the code
An object composed of refs
import { ref, reactive } from 'vue'
function useMouse () {
return {
x: ref(0),
y: ref(0)}}const { x } = useMouse()
const mouse = reactive(useMouse())
mouse.x === x.value
Copy the code
Converting asynchronous operations to “synchronous”
asynchronous
const data = await fetch('https: //api.github.com/').then(r= > r.json())
Copy the code
Modular API
const { data } = useFetch('https: //api.github.com').json()
const user_url = computed(() = > data.value.user_url)
Copy the code
useFetch
export function useFetch<R> (url: MaybeRef<string>) {
const data = shallowRef<T | undefined> ()const error = shallowRef<error | undefined>()
fetch(unref(url))
.then(r= > r.json())
.then(r= > data.value = r)
.catch(e= > error.value = error)
return {
data,
error
}
} // The implementation in Vueuse is actually much more complex than this
Copy the code
Side effect removal
useEventListener
import { onUnmounted } from 'vue'
export function useEventListener(target: EventTarget, name: string, fn: any) {
target.addEventListener(name, fn)
onUnmounted(() = > {
target.removeEventListener(name, fn)
})
}
Copy the code
Provide/Inject type security
Use the InjectionKey
type tool provided by VUE to share types in different contexts
// context.js
import { InjectionKey } from 'vue'
export interface useInfo {
id: number
name: string
}
export const injectKeyUser: InjectionKey<useInfo> = Symbol(a)Copy the code
// parent.vue
import { provide } from 'vue'
import { injectKeyUser } from './context.js'
export default {
setup () {
provide(injectKeyUser, {
name: 'xxx'.id: '7' // Type error, must be number}}})Copy the code
// children.vue
import { inject } from 'vue'
import { InjectionKey } from './context.js'
export default {
setup () {
const user = inject(InjectionKey)
if (user) {
//xxxx}}}Copy the code
State sharing
Because of the natural flexibility of composite apis, states can be created and used independently of components, which is why VUe3 can be used without vuex at all
// share.ts
import { reactive } from 'vue'
export const state = reactive({
foo: 1.bar: 'hello'
})
Copy the code
//A.vue
import { state } from './share.ts'
state.foo ++
Copy the code
// B.vue
import { state } from './share.ts'
console.log(state.foo) / / 2
Copy the code
useVModel
A tool to make using props and EMIT easier
export function useVModel (props, name) {
const emit = getCurrentInstance().emit
return computed(() = > {
get () {
return props[name]
},
set (v) {
emit(`update: ${name}`, v)
}
})
}
Copy the code
export default defineComponent({
setup(){
const value = useVModel(props, 'value')
return { value }
}
})
Copy the code
<template>
<input v-model="value">
</template>
Copy the code
The above is shared by AnthonyFu on vueConf2021