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,
生命周期之类,就像下图。
思考下面的例子:
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介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!