使用 setup
setup 选项应该是一个接受 props 和 context 的函数。
此外,我们从 setup 返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
setup 选项应该为一个函数
setup 选项函数接受两个参数: props 和 context
setup 选项函数需要返回要暴露给组件的内容
props:
(props 是响应式的,你不能使用 ES6 解构 如果不用toRefs将失去响应式 即子组件不能更新数据)
import { toRefs } from 'vue'
setup(props) {
const { title } = toRefs(props)
console.log(title.value)
}
context:
context 上下文是一个普通的 JavaScript 对象,它暴露三个组件的 property:
(它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构)
export default {
setup(props, context) {
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
}
}
解构版本
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
attrs 和 slots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.x 或 slots.x 的方式引用 property。请注意,与 props 不同,attrs 和 slots 是非响应式的。如果你打算根据 attrs 或 slots 更改应用副作用,那么应该在 onUpdated 生命周期钩子中执行此操作。
setup 函数的返回值
1. setup 函数的返回值 —— 对象
如果 setup 返回一个对象,则可以在组件的模板中像传递给 setup 的 props property 一样访问该对象的 property:
<template>
<!-- 模板中使用会被自动解开,所以不需要 .value -->
<div>{{ readersNumber }} {{ book.title }}</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// expose to template
return {
readersNumber,
book
}
}
}
</script>
2、setup 函数内部一般不使用 this
响应式系统 API
1. reactive
reactive() 接收一个普通对象然后返回该普通对象的响应式代理。等同于 2.x 的 Vue.observable()
<template>
<div id="app">{ state.count }</div>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
// state 现在是一个响应式的状态
const state = reactive({
count: 0,
})
return {
state
//...toRefs(state) 可以直接访问count
}
}
}
</script>
2. ref
接受一个参数值并返回一个响应式且可改变的 ref 对象,ref 对象拥有一个指向内部值的单一属性
.value
(对于基本数据类型,ref是自己的实现方式且性能优于reactive,而对于对象类型,ref仍然是通过reactive包装实现的)
<template>
<div>{{ count }}</div>
</template>
<script>
export default {
setup() {
return {
count: ref(0),
//如果想用ts的类型判断 得用 let count: Ref<number> = ref(1012)
//而不是 let count: <number> = ref(1012)
}
},
}
</script>
3. computed
3.1 传入一个 getter 函数,返回一个默认不可手动修改的 ref 对象
const count = ref(1)
const plusOne = computed(() => count.value + 1)
console.log(plusOne.value) // 2
plusOne.value++ // 错误!
3.2 传入一个拥有 get 和 set 函数的对象,创建一个可手动修改的计算状态。
const count = ref(1)
const plusOne = computed({
get: () => count.value + 1,
set: (val) => {
count.value = val - 1
},
})
plusOne.value = 1
console.log(count.value) // 0
4. readonly
传入一个对象(响应式或普通)或 ref,返回一个原始对象的只读代理。一个只读的代理是“深层的”,对象内部任何嵌套的属性也都是只读的。
const original = reactive({ count: 0 })
const copy = readonly(original)
watchEffect(() => {
// 依赖追踪
console.log(copy.count)
})
// original 上的修改会触发 copy 上的侦听
original.count++
// 无法修改 copy 并会被警告
copy.count++ // warning!
5. watchEffect
立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。
const count = ref(0)
watchEffect(() => console.log(count.value))
// -> 打印出 0
setTimeout(() => {
count.value++
// -> 打印出 1
}, 100)
//停止监听
const stop = watchEffect(() => {
/* ... */
})
// 之后
stop()
6.watch
import { reactive, ref, watch } from "vue";
const state = reactive({
count: 0,
});
//侦听时返回值得getter函数
watch(
() => state.count,
(count, prevCount) => {
// 1 0
console.log(count, prevCount);
}
);
state.count++;
const count = ref(0);
//直接侦听ref
watch(count, (count, prevCount) => {
// 2 0
console.log(count, prevCount, "watch");
},{ deep: true });
count.value = 2;
区别:
watchEffect不需要手动传入依赖
每次初始化时watchEffect都会执行一次回调函数来自动获取依赖
watchEffect无法获取到原值,只能得到变化后的值
生命周期钩子
onBeforeMount
onMounted
onBeforeUpdate
onUpdated
onBeforeUnmount
onUnmounted
onErrorCaptured
onRenderTracked
onRenderTriggered
import { onBeforeMount, onMounted } from "vue";
export default {
setup() {
console.log("----setup----");
onBeforeMount(() => {
// beforeMount代码执行
});
onMounted(() => {
// mounted代码执行
});
},
}
举例子
<template>
<div>{{ state.count }} * 2 = {{ double }}</div>
<div>{{ num }}</div>
<div @click="add">Add</div>
</template>
<script>
import { reactive, computed, ref } from "vue";
export default {
name: "Button",
setup() {
const state = reactive({
count: 1,
});
const num = ref(2);
function add() {
state.count++;
num.value += 10;
}
const double = computed(() => state.count * 2);
return {
state,
double,
num,
add,
};
},
};
</script>
应用
export default {
setup() {
const { networkState } = useNetworkState();
const { user } = userDeatil();
const { list } = tableData();
return {
networkState,
user,
list,
};
},
};
function useNetworkState() {}
function userDeatil() {}
function tableData() {}