Data declaration has been very straightforward in the past, but now there are many helper functions for us to use. The current rules are:
Use reactive
to declare Object, Array, Map, Set
Use ref
to declare String, Number, Boolean
Using reactive
for a primitive value will return a warning, And the value will not become reactive data.
/* DOES NOT WORK AS EXPECTED */ <script setup> import { reactive } from "vue"; const count = reactive(0); </script>
Paradoxically, another way is possible. For example, using ref
to declare an Array
will internally call reactive
.
Suppose you have a reactive object with a count
property, and a button to increment count
.
<template> Counter: {{ state.count }} <button @click="add">Increase</button> </template> <script> import { reactive } from "vue"; export default { setup() { const state = reactive({ count: 0 }); function add() { state.count++; } return { state, add, }; }, }; </script>
The above logic is fairly straightforward and works as expected, but you might be able to take advantage of JavaScript's destructuring to do the following:
/* DOES NOT WORK AS EXPECTED */ <template> <div>Counter: {{ count }}</div> <button @click="add">Increase</button> </template> <script> import { reactive } from "vue"; export default { setup() { const state = reactive({ count: 0 }); function add() { state.count++; } return { ...state, add, }; }, }; </script>
The code looks the same, and based on what we've seen before The experience should be feasible, but in fact, Vue's reactive tracking is through property access. This means that we cannot assign or destructure a reactive object because the reactive connection to the first reference has been broken. This is one of the limitations of using reactive helper functions.
Similarly, using a weird pattern of ref
can be hard to get used to.
Ref
Receives a value and returns a reactive object. The value is available inside the object under the .value
property.
const count = ref(0) console.log(count) // { value: 0 } console.log(count.value) // 0 count.value++ console.log(count.value) // 1
But ref
will be unpacked when used in a template file, and .value
is not required.
<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } </script> <template> <button @click="increment"> {{ count }} // no .value needed </button> </template>
But be careful! Unwrapping only works in top-level properties. The following code snippet generates [object Object]
.
// DON'T DO THIS <script setup> import { ref } from 'vue' const object = { foo: ref(1) } </script> <template> {{ object.foo + 1 }} // [object Object] </template>
Using .value
correctly takes time. Even though I sometimes forget how to use it, I use it more and more often.
Since the initial release of Vue, child components can communicate with parent components using emit
. You just need to add a custom event listener to listen for an event.
// 子组件 this.$emit('my-event') // 父组件 <my-component @my-event="doSomething" />
Now, emit
needs to be declared using defineEmits
.
<script setup> const emit = defineEmits(['my-event']) emit('my-event') </script>
Another thing to remember is that neither defineEmits
nor defineProps
need to be imported. They are automatically available when using script setup
.
<script setup> const props = defineProps({ foo: String }) const emit = defineEmits(['change', 'delete']) // setup code </script>
Finally, since the event must now be declared, there is no need to use the .native
modifier, in fact it has been removed.
Options API methods have several properties that are not supported in script setup
.
name
inheritAttrs
Custom options required for plugins or libraries
The solution is to set up two different scripts in the same component as defined by the script setup
RFC.
<script> export default { name: 'CustomName', inheritAttrs: false, customOptions: {} } </script> <script setup> // script setup logic </script>
Reactivity Transform is an experimental but controversial feature of Vue 3 that aims to simplify the way components are declared. The idea is to utilize compile-time transformations to automatically unpack a ref
and render .value
obsolete. But now it is abandoned and will be removed in Vue 3.3. It's still available as a package, but since it's not part of Vue core, it's best not to invest time in it.
Previously, asynchronous components were declared by wrapping them in a function.
const asyncModal = () => import('./Modal.vue')
Starting from Vue 3, asynchronous components need to be explicitly defined using the defineAsyncComponent
helper function.
import { defineAsyncComponent } from 'vue' const asyncModal = defineAsyncComponent(() => import('./Modal.vue'))
In Vue 2, component templates require a single root element, which sometimes introduces unnecessary wrapped elements.
<!-- Layout.vue --> <template> <div> <header>...</header> <main>...</main> <footer>...</footer> </div> </template>
This is no longer necessary as multiple root elements are now supported. ????
<!-- Layout.vue --> <template> <header>...</header> <main v-bind="$attrs">...</main> <footer>...</footer> </template>
All component lifecycle events have been renamed, either by adding the on
prefix, or by changing the name entirely. You can see all the changes in the chart below.
The above is the detailed content of What are the mistakes to avoid in Vue3. For more information, please follow other related articles on the PHP Chinese website!