+6

Vue v3.3 có gì hot 🔥

I. Giới thiệu

Hello everyone ✌️, bài viết này mình muốn chia sẻ các thông tin và chức năng mới của phiên bản Vue 3.3

  • <script setup> + TypeScript

    • Imported and Complex Types Support in Macros
    • Generic Components
    • More Ergonomic defineEmits
    • Typed Slots with defineSlots
  • Tính năng thử nghiệm

    • Reactive Props Destructure
    • defineModel
  • Các tính năng đáng chú ý khác

    • defineOptions
    • Better Getter Support with toRef and toValue
    • JSX Import Source Support

II. Nội dung

Phiên bản này tập trung vào các cải tiến về trải nghiệm cho các lập trình viên, cụ thể là SFC <script setup> + Typescript.

Cùng với phiên bản v1.6 của Vue Language Tools (trước đây gọi là Volar) đã giải quyết được nhiều điểm khó khăn tồn tại từ lâu khi sử dụng Vue với TypeScript.

Dependency Updates

  • volar / vue-tsc@^1.6.4
  • vite@^4.3.5
  • @vitejs/plugin-vue@^4.2.0
  • vue-loader@^17.1.0 (if using webpack or vue-cli)

<script setup> + TypeScript

1. Imported and Complex Types Support in Macros

Ở các version < 3.3, các kiểu dữ liệu được định nghĩa cho defineProps hay defineEmits chỉ giới hạn ở các kiểu dữ liệu cục bộ...

// Hoạt động bình thường
<script setup lang="ts">
interface Props {
    title: string        
}    
    
defineProps<Props>()
</script>
// Xảy ra lỗi
<script setup lang="ts">
import type { Props } from './foo'
    
defineProps<Props>()
</script>

Hạn chế này đã được giải quyết ở version 3.3

<script setup lang="ts">
import type { Props } from './foo'

// imported + intersection type
defineProps<Props & { extraProp?: string }>()
</script>

2. Generic Components

Các Components ở phiên bản mới sử dụng <script setup> đã có thể thêm generic type thông qua attribute generic :

Simple T

<script setup lang="ts" generic="T">

  defineProps<{
    list: T[],
    modelValue?: T
  }>

  defineEmits<{
    (e: `update:ModelValue`, a: T): void
  }>()
    
</script>

Extend types...

<script setup lang="ts" generic="T extends string | number, U extends Item">
    
import type { Item } from './types'
defineProps<{
  id: T
  list: U[]
}>()
    
</script>

3. More Ergonomic defineEmits

Từ phiên bản v3.3, đã có thêm cách khai báo kiểu dữ liệu cho tham số của defineEmits một cách thuận tiện hơn như sau.

// BEFORE
const emit = defineEmits<{
  (e: 'foo', title: string): void
  (e: 'bar', id: number, ...rest: any[]): void
}>()
// AFTER
const emit = defineEmits<{
  foo: [title: string]
  bar: [id: number, ...rest: any[]]
}>()

4. Typed Slots with defineSlots

Trong Vue v3.3 defineSlots là một phương thức được sử dụng để định nghĩa các nội dung (slot) cần được chèn vào Component trong Vue Composition API.

<script setup lang="ts">
defineSlots<{
  default?: (props: { msg: string }) => any
  item?: (props: { id: number }) => any
}>()
</script>

Tính năng thử nghiệm

1. Reactive Props Destructure

Tính năng này cung cấp cách khai báo giá trị mặc định cho props một cách thuận tiện hơn.

<script setup>
import { watchEffect } from 'vue'

const { msg = 'hello' } = defineProps(['msg'])

watchEffect(() => {
  // accessing `msg` in watchers and computed getters
  // tracks it as a dependency, just like accessing `props.msg`
  console.log(`msg is: ${msg}`)
})
</script>

<template>{{ msg }}</template>

2. defineModel

Đây là một tính năng mình thấy rất hay ở phiên bản lần này.

Ở các phiên bản trước, Vue hỗ trợ two-way binding với v-model bằng cách khai báo propemit để nhận và update cho giá trị đó.

<!-- BEFORE -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
console.log(props.modelValue)

function onInput(e) {
  emit('update:modelValue', e.target.value)
}
</script>

<template>
  <input :value="modelValue" @input="onInput" />
</template>

Nhưng từ version 3.3, chúng ta chỉ cần sử dụng defineModel

defineModel sẽ tự động đăng ký một prop và trả về một tham chiếu có thể thay đổi, cập nhật trực tiếp.

<!-- AFTER -->
<script setup>
const modelValue = defineModel()
console.log(modelValue.value)
</script>

<template>
  <input v-model="modelValue" />
</template>

Các tính năng đáng chú ý khác

Bên cạnh các tính năng mới được giới thiệu ở trên, thì ở phiên bản này tác giả cũng có những thay đổi và cập nhật cho những tính năng đã xuất hiện ở các phiên bản trước.

1. defineOptions

defineOptions cho phép bạn tùy chỉnh các option của Component một cách tường minh và linh hoạt hơn.

import { defineOptions } from 'vue';

const MyComponent = defineOptions({
  name: 'MyComponent',
  props: {
    message: String
  },
  data() {
    return {
      counter: 0
    };
  },
  methods: {
    increment() {
      this.counter++;
    }
  },
  template: `
    <div>
      <p>{{ message }}</p>
      <button @click="increment">Increment</button>
      <p>Counter: {{ counter }}</p>
    </div>
  `
});

2. Cập nhật toReftoValue

toRef đã được cải tiến để chuẩn hóa các giá trị, getters, refs thành refs

// equivalent to ref(1)
toRef(1) // e.g: Ref<number>
// creates a readonly ref that calls the getter on .value access
toRef(() => props.foo)
// returns existing refs as-is
toRef(existingRef)

Bạn có thể sử dụng toRef để cập nhật lại sự thay đổi giá trị gần tương tự như computed.

Chức năng toValue trong Vue được sử dụng để lấy giá trị hiện tại của một thuộc tính đang theo dõi. Nó có thể được sử dụng trên bất kỳ thuộc tính nào, bao gồm cả thuộc tính được tạo bằng ref hoặc computed.

toValue(1) //       --> 1
toValue(ref(1)) //  --> 1
toValue(() => 1) // --> 1

toValue có thể sử dụng để thay thế cho unRef

const myRef = ref(0);
console.log(toValue(myRef)); // 0

myRef.value = 1;
console.log(toValue(myRef)); // 1

III. Tổng kết

Đây là những thông tính năng mới về phiên bản VueJS v3.3. Cảm ơn các bạn đã theo dõi bài viết của mình nhé.

Tham khảo

https://vuejs.org/api/reactivity-utilities.html

https://blog.vuejs.org/posts/vue-3-3


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.