- Breaking change
- Composition API (React Hook phiên bản Vue)
- Vue Fragment
- Mét nhét component vào chỗ nào trong DOM cũng được
- Suspense (lại chôm của React)
- Đa vũ trụ - à không đa v-model
Breaking change
Nếu đang dùng Vue 2 và muốn chuyển lên Vue 3 sử dụng, có một điểm breaking change (không sửa không được, chết hết)
Nếu đang dùng Vue 2, chúng ta new
một object Vue
new Vue({
el: "#app",
template: "<div>{{message}}</div>",
data: { message: "Hello World!" },
})
thì Vue 3 chúng ta gọi hàm Vue.createApp
const app = Vue.createApp({
template: "<div>{{ message }}</div>",
data() {
return {
message: "Hello World!"
}
}
});
app.mount("#app");
Điểm cần lưu ý thêm là data
trong Vue phải luôn là một phương thức thay vì object như trước đây
Việc mount global component cũng sẽ chuyển cho app
thay vì gắn vào Vue instance như trước
// vue 2
Vue.component('my-button', {
template: '<button @click="updateValue">Click to update!</button>',
methods: {
updateValue() {
this.$emit('update');
},
}
})
// vue 3
const app = Vue.createApp(/* app config */);
app.component('my-button', {
emits: ["update"],
template: '<button @click="updateValue">Click to update!</button>',
methods: {
updateValue() {
this.$emit('update');
},
},
})
app.mount("#app");
Tương tự với Router và Store
// vue 2
Vue.use(VueRouter);
Vue.use(Vuex);
const store = new Vuex.Store(/* store config */);
const router = new VueRouter(/* router config */);
new Vue({
store,
router,
render: (h) => h(App),
}).$mount('#app');
// vue 3
const store = createStore(/* store config */);
const router = createRouter(/* router config */);
const app = createApp(/* app config */);
app.use(store);
app.use(router);
app.mount('#app');
Composition API (React Hook phiên bản Vue)
Cái này vai mượn ý tượng của team React quá luôn nha các bạn.
Với Vue 2 khai báo các thuộc tính của component bằng Option API
<template>
<div>
<h2>List of items:</h2>
<ul>
<li v-for="item in list" :key="item">{{ item }}</li>
</ul>
<div>
<label>
Name:
<input name="name" v-model="inputValue"/>
</label>
</div>
<button @click="addItem"></button>
</div>
</template>
<script>
export default {
data() {
return {
inputValue: "",
list: [],
};
},
computed: {
itemsCount() {
return this.item.list.length();
},
},
methods: {
addItem() {
this.list.push(this.inputValue);
this.inputValue = "";
},
},
};
</script>
Hạn chế của Option API, logic của component nằm rải rác ở nhiều chỗ trong computed
, data
, methods
, muốn sử dụng lại các logic này cũng khó khăn, dùng mixins
thì nó lại không rõ ràng.
Composition API được giới thiệu để giải quyết vấn đề trên
<template>
<div>
<h2>List of items:</h2>
<ul>
<li v-for="item in list" :key="item">{{ item }}</li>
</ul>
<div>
<label>
Name:
<input name="name" v-model="inputValue"/>
</label>
</div>
<button @click="addItem"></button>
</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
setup() {
const inputValue = ref('')
const list = ref([]);
const itemsCount = computed(function() {
return list.value.length()
})
function addItem() {
list.value.push(this.inputValue.value)
inputValue.value = '';
}
return {
inputValue,
list,
itemsCount,
addItem
}
}
}
</script>
Việc sử dụng Composition API hay Option API là tùy chúng ta, Vue 3 hỗ trợ hết.
Muốn sử dụng lại logic này ở những component khác, viết tách function ở trên ra
import { ref, computed } from 'vue';
export const useList = () => {
const inputValue = ref('')
const list = ref([]);
const itemsCount = computed(function() {
return list.value.length()
})
function addItem() {
list.value.push(this.inputValue.value)
inputValue.value = '';
}
return {
inputValue,
list,
itemsCount,
addItem
}
}
Sau đó trong component muốn sử dụng
export default {
setup() {
const {
inputValue,
list,
itemsCount,
addItem
} = useList();
return {
inputValue,
list,
itemsCount,
addItem
}
}
}
Vue Fragment
Hồi xưa chúng ta chỉ được phép nhét giữa <template/>
một element, giờ nhét mấy cái element cũng được hết
<template>
<div class="element-1"></div>
<div class="element-2"></div>
</template>
Mét nhét component vào chỗ nào trong DOM cũng được
Ngày xưa component khai báo ở đâu thì sẽ được render ở vị trí đó trong DOM, ngày nay, với <teleport/>
component thì component có thể được render vào ví trí bất kỳ mà chúng ta khai báo
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
Suspense (lại chôm của React)
Nói chung bạn nào đã biết Suspense React thì Vue nó y chang vậy đó.
Khi bị lỗi, không render được component, Suspense sẽ được đắp vào thay thế
<template>
<Suspense>
<template #default>
<div v-for="item in articleList" :key="item.id">
<article>
<h2>{{ item.title }}</h2>
<p>{{ item.body }}</p>
</article>
</div>
</template>
<template #fallback>
Articles loading...
</template>
</Suspense>
</template>
Đa vũ trụ - à không đa v-model
Ngày xưa, v-modal chỉ được phép sử dụng với một giá trị, ngày nay, v-modal thích xài bao nhiêu thì xài
<template>
<survey-form v-model:name="name" v-model:age="age"> </survey-form>
</template>
//SurveyForm.vue
<template>
<div>
<label>Name: </label>
<input :value="name" @input="updateName($event.target.value)" />
<label>Age: </label>
<input :value="age" @input="updateAge($event.target.value)" />
</div>
</template>
<script>
export default {
props: {
name: String,
age: Number,
},
setup(props, { emit }) {
const updateName = (value) => {
emit('update:name', value);
};
const updateAge = (value) => {
emit('update:age', +value);
};
return { updateName, updateAge };
},
};
</script>
Một vài nâng cấp không nhìn thấy được như source code dùng TypeScript hoàn toàn, nâng cao tốc độ,
Tham khảo
Initializing...