Responsive Props Destruction
Props in Vue3.5 officially supports deconstruction and adds responsive tracking
Set default values
Declare props default values using JavaScript native default value syntax
before
const props = withDefaults( defineProps<{ count?: number msg?: string }>(), { count: 0, msg: 'hello' } )
Now
const { count = 0, msg = 'hello' } = defineProps<{ count?: number message?: string }>()
Responsive destruction
When accessing variables deconstructed by defineProps in the same <script setup> code block, the Vue compiler will automatically add props in front of it
before
const { foo } = defineProps(['foo']) watchEffect(() => { // Run only once before 3.5 (foo) })
Now
const { foo } = defineProps(['foo']) watchEffect(() => { // Re-execute in 3.5 when the "foo" prop changes (foo) // `foo` is converted from the compiler to ``, the above is equivalent to `()`})
Similarly, listening to a deconstructed prop variable or passing it into a composable item while preserving responsiveness requires wrapping it in a getter
before
const { foo } = defineProps(['foo']) watch(foo, /* ... */)
Now:
// watch(foo, /* ... */) is equivalent to watch(, ...). We pass a value to watch instead of a responsive data sourcewatch(() => foo, /* ... */) // Pass the deconstructed prop to the external function and maintain responsivenessuseComposable(() => foo)
Listening (watch/watcheffect) related
watch supports specified depth: number
The deep option of watch now supports passing in numbers to specify the depth of the listener
const state = ref({ a: { b: { c: 1 } } }) watch(state, (newValue) => { (`state: ${newValue}`) }, { deep: 2 } ) = { c: 2 } // Change the properties of the second layer to trigger listening = 2 // The properties of the third layer have been changed and listening is not triggered
Cleaning function onWatcherCleanup / onEffectCleanup
In the past, when we wanted to send an asynchronous request in the listening function, the request parameters were likely to change. At this time, we need to set up the global variable storage AbortController and clean it before the component is uninstalled.
import { watch, onBeforeUnmount } from "vue" let controller = new AbortController() watch(state, (newValue) => { () // Cancel the last request controller = new AbortController() fetch(`/api/${newValue}`, { signal: }).then(() => { // Callback logic }) }); // Clean up the components before uninstallingonBeforeUnmount(() => ())
Now that we have the cleaning function onWatcherCleanup / onEffectCleanup, we can call it directly to clean up the previous call (asynchronous) function/request
import { watch, onWatcherCleanup } from 'vue' watch(id, (newId) => { const controller = new AbortController() fetch(`/api/${newId}`, { signal: }).then(() => { // Callback logic }) onWatcherCleanup(() => { // Terminate expiration request () }) })
The onEffectCleanup function is written similar to the above, the difference is the import source
import { onEffectCleanup } from "@vue/reactivity";
[!WARNING]
onWatcherCleanup is only supported in Vue 3.5+ and must be called during synchronous execution of watchEffect effect function or watch callback function: you cannot call it after the await statement of the asynchronous function.
watch return value enhancement
The watch return value has been added to the pause/restoring listener, which can control the listening range more carefully
const { stop, pause, resume } = watch(() => {}) // Pause the listenerpause() // Recover laterresume()
SSR Improvements
Lazy Activation Lazy Hydration
Asynchronous components can control when activation is performed through the hydrate option in the defineAsyncComponent() API
Activate when free
import { defineAsyncComponent, hydrateOnIdle } from 'vue' const AsyncComp = defineAsyncComponent({ loader: () => import('./'), hydrate: hydrateOnIdle(/* Pass optional maximum timeout */) })
Activate when the element becomes visible
import { defineAsyncComponent, hydrateOnVisible } from 'vue' const AsyncComp = defineAsyncComponent({ loader: () => import('./'), hydrate: hydrateOnVisible() })
Customize the policy
import { defineAsyncComponent, type HydrationStrategy } from 'vue' const myStrategy: HydrationStrategy = (hydrate, forEachElement) => { // forEachElement is a helper function that traverses all root elements in the DOM that is not activated by the component. // Because the root element may be a fragment rather than a single element forEachElement(el => { // ... }) // Call `hydrate` when ready` hydrate() return () => { // Return a destroy function if necessary } } const AsyncComp = defineAsyncComponent({ loader: () => import('./'), hydrate: myStrategy })
other
Please checkVue3 official documentation - lazy activation, I won't repeat it here
useId() Generates a unique application ID
Used to generate an in-app unique ID for accessibility attributes or form elements. In our daily applications, we can mainly solve the problem of different ids generated by the server and client, resulting in rendering errors caused by different renderings
<script setup> import { useId } from 'vue' const id = useId() </script> <template> <form> <label :for="id">Name:</label> <input : type="text" /> </form> </template>
data-allow-mismatch
If the client value inevitably differs from its server-side corresponding value (such as date), we can use the property data-allow-mismatch to avoid the resulting activation mismatch warning
<span data-allow-mismatch>{{ () }}</span>
You can also specify specific types. Allowed values are: text, children (only allow direct child components to mismatch), class, style, attribute
other
useTemplateRef()
Return a shallow ref, which can bind elements more intuitively, and also supports dynamic binding.
<script setup> import { ref, useTemplateRef, onMounted } from 'vue' const targetRef = ref('input1') const inputRef = useTemplateRef<HTMLInputElement>() onMounted(() => { () }) </script> <template> <input ref="input1" /> <input ref="input2" /> </template>
I won't explain other things that are not commonly used
This article about this article about Vue3.5's common features will be introduced here. For more relevant content on Vue3.5, please search for my previous articles or continue browsing the related articles below. I hope you will support me in the future!