6

Vue 3.0 上手(一)基础 API 的上手

 3 years ago
source link: http://www.yukapril.com/2020/08/16/vue-3.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Vue 3.0 上手(一)基础 API 的上手

2020 年年初,Vue 的 3.0 alpha 版本就发布了。五一前后,beta 版页开始了。按照计划,预计十一前就可以发布正式版了。新的 Vue 和 React 一样,加入了 Hooks 方案,叫做 composition-api组合式 API)。我比较感兴趣,也比较关注 composition-apiReact-hooks 的一些区别,特来上手体验一番。

本篇文章开始写于 2020 年 7 月底,当时为 3.0.0-rc.2。后来部分内容已经升级到 3.0.0-rc.5

Vue 3.0 目前还需要通过 2.0 的架子升级而来。

  1. 全局安装 vue-cli

    1
    npm install -g @vue/cli
  2. 创建一个测试项目,创建项目时候,要把需要的功能都选择上,否则后续自己升级比较麻烦

    1
    vue create vue-next-test
  3. 把测试项目,升级为 vue-next(Vue 3.0)

    1
    2
    cd vue-next-test
    vue add vue-next
  4. 所有的文件,都将会被升级。之后就可以愉快玩耍 vue-next(Vue 3.0)了。

文档和新增内容

我只参考了官方的文档,参见这里:组合式 API 征求意见稿 和这里 API 参考

Vue 3 新增了很多语法、API,以及 Vue 3 对于 Vue 2 的变化等。故需要学习的点主要有:

  • 项目中 Vue 的实例启动引导,如改用 createApp 创建 Vue 实例等;
  • 基础响应式系统API:reactive ref computed readonly watchEffect watch。其中 ref 的理解、以及 ref 拆包是重中之重;
  • 生命周期钩子:onBeforeMount onMounted onBeforeUpdate onUpdated onBeforeUnmount onUnmounted onErrorCaptured,以及和原有钩子关系;
  • 依赖注入:provide inject,提供类似简易 VueX 的能力;
  • html 模板中使用 ref 获取 DOM 元素;
  • 响应式工具:unref toRef toRefs isRef isProxy isReactive isReadonly
  • 高级API:customRef markRaw shallowReactive shallowReadonly shallowRef toRaw

我认为,以上内容大部分都需要比较熟悉,除了:

  1. 生命周期可以只看自己常用的,剩下的大部分估计很少用到;
  2. 依赖注入可以先不看,等其他都了解后,再学习也不迟;
  3. 响应式工具中,is 开头的判断工具可以不着急,目前来看,一般项目开发应该用不到;但 ref 系列工具得了解,真正做项目时候要用的;
  4. 高级 API 不用着急,这些都是提供更强大的自定义能力,目前感觉主要作用还是来提升性能的,可以后续了解学习。

基础 API 的上手

过于基础的演示,可以自行查看官方例子以及尝试下。这里仅说明我遇到的一些细节点。

setup 的返回值中 state 处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
setup () {
const state = reactive({
count: 0,
sum: computed(() => state.count * 9.99)
})

const onAddCountClick = () => {
state.count++
}

const onTimeoutAddCountClick = () => {
setTimeout(() => {
state.count++
}, 1000)
}

return {
// ...state <-- 错误,不能展开,否则会失去响应
// count: state.count <-- 错误,同样不可以返回数值型,也会失去响应
// 必须直接返回 state
state,
onAddCountClick,
onTimeoutAddCountClick,
}
}

返回 state 时,不能进行展开返回,否则会失去响应式。

此外,在事件中增加 state 数值,和 React-hooks 截然不同。Vue 写 setTimeout 异步增加数值,最终真的会多次改变数值,相当于每次执行逻辑都会获取最新的 state,这点非常容易理解。React 则完全不同,React 需要采用 ref 才可以实现多次改变数值。

watchEffect / watch

watchEfflect 相当于 React-hooks useEffect

watch 就是 Vue2.0 中的 $watch

watchEffect/watch 区别:

  • watchEffect 会立即执行一次,watch 只有在观察对象改变时执行
  • watchEffect 自动收集那些元素需要观察,watch 需要主动声明
  • watchEffect 只关注改变及改变后的结果,watch 关注改变同时关注改变前后的具体内容
  • watchEffect 默认是在状态改变并视图更新后触发(可以配置为状态改变后触发以及视图更新同时触发,和 React-hooks useEffect useLayoutEffect 差不多的意思),watch 估计是状态改变并视图更新后触发。在默认不改变 watchEffectflush 情况下,watchEffect watch 代码先写谁,谁就被先执行。

此外,两者都支持停止侦听清除副作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
setup () {
const state = reactive({
count: 0
})

const onAddCountClick = () => {
state.count++
}
// watchEffect 相当于 React-hooks useEffect
// 只不过不需要手动指定依赖项
watchEffect(() => {
console.log('[watchEffect]', state.count)
}, { flush: 'pre' })
return {
state,
onAddCountClick,
}
// watch 要求指定观察对象的,和Vue2.0的$watch基本相同
// vm.$watch('a.b.c', function (newVal, oldVal) {
// do something..
// })
watch(
() => state.sum,
(newVal, oldVal) => {
console.log('[watch]', newVal, oldVal)
}
)
}

如果需要关注数值前后的变化,还是要用 watch

如果仅仅关注新值,可以使用更简单的 watchEffect。比如状态改变时,触发请求服务器。这样写还可以省去单独触发第一次默认请求。

不过要注意的是,要保证 watchEffect 流程稳定。这一点类似于 React-hooks 的 useState 数量顺序必须一致。例如:

1
2
3
4
5
6
watchEffect(() => {
const rnd = Math.random() > 0.5
if (!rnd) {
console.log(state.count)
}
})

一旦 rndtrue,则后续 state.count 无论怎么变化,也不会触发 watchEffect 了。

Ref 是包裹对象,和 React ref类似

注意:computed 也是 ref 的一个特例。

1
2
3
4
5
6
7
8
9
10
11
12
setup () {
const count = ref(0)

const onAddCountClick = () => {
count.value++
}

return {
count, // 由于 ref 本身就是对象,所以可以直接进行返回
onAddCountClick,
}
},

ref 包裹的内容,要使用 .value 进行拆包后取值或者操作,如 count.value++

但,以下情况除外:

  • 在模板中使用,会自动解析 .value,无需人工拆包,例如直接写:<p></p>
  • 在响应式方法中,比如 computed 就是 ref 高级用法,以及在 reactive 中,无需 .value。例如:
1
2
3
4
5
6
7
8
9
const count = ref(0)
const count1 = reactive({ count })
const count2 = reactive([count])
const count3 = computed(() => count1)

console.log('[Ref]0:', count.value)
console.log('[Ref]1:', count1.count) // 对象形式reactive,不用写也不能写 count1.count.value,因为会自动拆包
console.log('[Ref]2:', count2[0].value) // 非对象形式的reactive,必须手动拆包
console.log('[Ref]3:', count3.value.count) // computed 需要手动拆包

ref 应该非常常用,犹如 React-hooks 中一样重要。除了 reactive 保存响应式数据外,引用数据就靠 ref 了。

Readonly

1
2
3
4
5
6
7
const origin = reactive({ count: 0 })
const copy = readonly(origin)
origin.count++
console.log('[readonly]1:', origin.count)
console.log('[readonly]2:', copy.count)
copy.count++ // 无法修改,会被warn警告,但不是报错
console.log('[readonly]3:', copy.count)

Vue 的开发者不就是反复修改 state 么,我没想出为啥要出这个。我唯一想到的就是,父组件给子组件传参,参数是对象,此时可以用 readonly,防止子组件修改参数。能想到这个,是因为早期我就是这么操作来实现父子组件通讯的…

–END–

分享到

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK