Composition API简介
你可以通过下面两个api创建响应性对象:
reactive()ref()/computed()
reactive简介
reactive(obj) 会返回一个响应性对象,对象的所有属性都具备响应性。
例如:
// 模板: {{ state.a }} - {{ state.b }}
const state = reactive({ a: 3 })
// 渲染结果: 3 - undefined
state.a = 5
state.b = 'bye'
// 渲染结果: 5 - bye
他和vue2的data属性是一样的,但是他可以给对象添加新的属性,属性也具备响应性,因为vue3是基于proxy实现的。
Ref简介
Ref相当于一个包含.value属性的简单对象,就像下面Typescript的定义:
interface Ref<A> {
value: A
}
两个方法创建 refs:
ref().value支持读取和赋值
computed().value只支持读取
例子:
const countRef = ref(0) // { value: 0 }
const countPlusOneRef = computed(() => countRef.value + 1) // { value: 1 }
countRef.value = 5
/*
* countRef is { value: 5 }
* countPlusOneRef is { value: 6 } (readonly)
*/
推荐ref而非reactive
这只是我在使用compostion api实践总结的小小观点,并不具备权威性,你也可以试一下,告诉我你的观点。
在使用compostion api前,我以为reactive会是首选API,因为它不需要通过.value读取值。但是,我使用compostion api 一段时间后,我不再使用reactive!
三个理由:
-
便利性 -
ref()允许自由的定义一个响应性变量。 -
灵活性 -
ref()允许替换整个对象 -
明确性 -
.value明确告诉你正在做什么
1. 便利性
composition api 提供一种以组件功能为维度组合逻辑的方法,他不同于options api把逻辑分别定义在data, computed, methods, 生命周期之类,就像下图。
![[译]关于vue3 compostion api "reactive()"方法的害处](https://img.wangzhan5u.com/images/5/[y]gyvipoyrfrbsh.jpg)
思考下面的例子:
const state = reactive({
count: 0,
errorMessage: null,
})
setTimeout(() => state.count++, 1000)
watch(state.count, count => {
if (count > 10) {
state.errorMessage = 'Larger than 10.'
}
})
如果使用reactive() 先定义所有属性,会导致像vue2那样,以特性划分代码,而不是根据逻辑划分,这会导致你的业务逻辑代码分散到不同地方。
const count = ref(0)
setTimeout(() => count.value++, 1000)
const errorMessage = ref(null)
watch(count, count => {
if (count > 10) {
errorMessage.value = 'Larger than 10.'
}
})
如果用ref()你可以自由的创建响应变量,看到例子上,我只会在我需要响应变量时才定义他们,这会让逻辑更直观。
2.灵活性
I initially thought the sole purpose of ref() was to enable primitive values to be reactive. But it can become extremely handy too when using ref() with objects.
我最初认为ref() 只是用来把原始类型声明为响应性,但是,当ref()和对象一起使用,它也是非常方便的。
思考:
const blogPosts = ref([])
blogPosts.value = await fetchBlogPosts()
如果我用reactive实现相同的功能,我需要遍历数组。
const blogPosts = reactive([])
for (const post of (await fetchBlogPosts())) {
blogPosts.push(post)
}
或者使用 Array.prototype.splice()
const blogPosts = reactive([])
blogPosts.splice(0, 0, ...(await fetchBlogPosts()))
上面例子使用ref()明显比较简单,因为你只需要把新的数组替换旧的数组即可。再看看下面这个分页例子:
watch(page, page => {
// 删除所以内容
while (blogPosts.length > 0) {
blogPosts.pop()
}
// 添加新数据
for (const post of (await fetchBlogPostsOnPage(page))) {
blogPosts.push(post)
}
})
或者用 splice
watch(page, page => {
blogPosts.splice(0, blogPosts.length, ...(await fetchBlogPostsOnPage(page)))
})
但是用 ref()
watch(page, page => {
blogPosts.value = await fetchBlogPostsOnPage(page)
})
这会非常灵活.
3. 明确性
reactive() 返回的对象和非响应性对象是相同的,当你需要处理其他非响应性对象时,容易造成混淆。
watch(() => {
if (human.name === 'Jason') {
if (!partner.age) {
partner.age = 30
}
}
})
上面的代码,你没法知道human和partner哪个是响应对象,但是用ref()就不会有这个问题
.value 看起来有点啰嗦,但是这可以提醒你这是响应对象。
watch(() => {
if (human.value.name === 'Jason') {
if (!partner.age) {
partner.age = 30
}
}
})
现在很显然human是响应性对象,partner不是
结论
上面只是我的初步看法,你的看法是怎样的,评论区见
原文地址:dev.to/ycmjason/th…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!