目录
一、setup
二、ref 传入原始数据类型
三、reactive 传入对象类型
四、生命周期钩子函数
setup 函数是 composition API(组合式 API) 的一个入口点
✦ 调用时机
先创建组件实例,再初始化 props,紧接着调用 setup 函数。从生命周期钩子视角来看,setup 函数会在 beforeCreate 钩子之前被调用
✦ 模版中使用
如果 setup 返回一个对象,则对象的属性将会被合并到组件模版的渲染上下文
{
{ count }} {
{ object.foo }}
注意:setup 返回的 ref 在模版中会自动解开,不需要写 .value 属性
✦ 渲染函数 / JSX 中使用
setup 也可以返回一个函数,函数中也能使用当前 setup 函数作用域中的响应式数据
import { h, ref, reactive } from 'vue'
export default {
setup() {
const count = ref(0)
const object = reactive({ foo: 'bar' })
return () => h('div', [count.value, object.foo])
},
}
✦ setup 参数
setup 函数接收 props 作为它的第一个参数
export default {
props: {
name: String,
},
setup(props) {
console.log(props.name)
},
}
props 对象是响应式的,watchEffect 或 watch 会观察和响应式 props 更新
export default {
props: {
name: String,
},
setup(props) {
watchEffect(() => {
console.log(`name is: ` + props.name)
})
},
}
不要解构 props 对象,那样会使其失去响应式
export default {
props: {
name: String,
},
setup({ name }) {
watchEffect(() => {
console.log(`name is: ` + name) // Will not be reactive!
})
},
}
setup 函数第二个参数提供了一个上下文对象 context
const MyComponent = {
setup(props, context) {
context.attrs
context.slots
context.emit
},
}
attrs 和 slots 都是内部组件实例上对应项的代理,可以确保在更新后仍然是最新值。可以解构无需担心后面访问到过期的值
const MyComponent = {
setup(props, { attrs }) {
// 一个可能之后回调用的签名
function onClick() {
console.log(attrs.foo) // 一定是最新的引用,没有丢失响应性
}
},
}
✦ this 用法
this 在 setup 函数中不可用
✦ 类型定义
interface Data {
[key: string]: unknown
}
interface SetupContext {
attrs: Data
slots: Slots
emit: (event: string, ...args: unknown[]) => void // void 表示一个函数不需要返回值
}
function setup(props: Data, context: SetupContext): Data
为了获得传递给
setup()
参数的类型推断,需要使用 defineComponent (定义组件)方法
ref 是一个函数,它接受一个参数,返回一个神奇的响应式对象
接受一个参数值并返回一个响应式且可改变的 ref 对象
ref 对象拥有一个指向内部值的单一属性 .value
const count = ref(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
✦ 模版中访问
当 ref 在 setup() 返回的对象中,并在模板中使用时,它会自动解套,无需在模板内额外书写 .value
{
{ count }}
✦ 作为响应式对象的属性访问
当 ref 作为 reactive 对象的 property 被访问或修改时,也将自动解套 value 值,其行为类似普通属性
const count = ref(0)
const state = reactive({
count,
})
console.log(state.count) // 0
state.count = 1
console.log(count.value) // 1
注意当嵌套在 reactive Object 中时,ref 才会解套。从 Array 或者 Map 等原生集合类中访问 ref 时,不会自动解套
const arr = reactive([ref(0)])
// 这里需要 .value
console.log(arr[0].value)
const map = reactive(new Map([['foo', ref(0)]]))
// 这里需要 .value
console.log(map.get('foo').value)
✦ 类型定义
interface Ref {
value: T
}
function ref(value: T): Ref
有时我们可能需要为 ref 做一个较为复杂的类型标注。我们可以通过在调用 ref 时传递泛型参数来覆盖默认推导:
const foo = ref('foo') // foo 的类型: Ref
foo.value = 123 // 能够通过!
✦ 案例
{
{count}}
{
{double}}
接收一个普通对象然后返回该普通对象的响应式代理
const obj = reactive({ count: 0 })
✦ 类型定义
function reactive(raw: T): T
✦ 案例
{
{count}}
{
{double}}
- {
{item}}
{
{person.name}}
✦ 使用 ref 还是 reactive 可以使用以下准则:
1) 使用 ref 传入原始类型,使用 reactive 传入对象类型
2) 所有场景都使用 reactive,但一定要记得使用 toRefs API 保证 reactive 对象属性保持响应性
可以直接导入 onXXX 一族的函数来注册生命周期钩子
生命周期钩子注册函数只能在 setup() 期间同步使用, 因为它们依赖于内部的全局状态来定位当前组件实例
与 2.x 版本生命周期相对应的组合式 API
beforeCreate
setup()
created
setup()
beforeMount
-> onBeforeMount
mounted
-> onMounted
beforeUpdate
-> onBeforeUpdate
updated
-> onUpdated
beforeDestroy
-> onBeforeUnmount(unmount 卸载)
destroyed
-> onUnmounted
errorCaptured
-> onErrorCaptured(captured 捕获)
Vue3.0 新增调试钩子函数,两个钩子函数都接收一个 DebuggerEvent
onRenderTracked(Tracked 跟踪)
onRenderTriggered(Triggered 触发)
{
{msg}}
参考文档:
vue3.0 composition api 官方文档
免费 DOG API
https://www.jianshu.com/p/03862c7bf35adocument.title API
课程文档
http://docs.vikingship.xyz/typescript.html
https://shimo.im/docs/YT9cdpDcKKCWV3CX/read
API
https://thecatapi.com/
https://api.thecatapi.com/v1/images/search?limit=1
https://dog.ceo/dog-api/