Vue 3的响应式系统是其核心特性之一,除了在组件内部使用响应式数据,我们还可以创建独立的响应式实例,这些实例不依赖特定组件的生命周期,能够在多个场景中被复用和共享。
独立响应式实例的创建方式
使用reactive创建对象类型响应式实例
reactive函数可以将一个普通的对象转换为响应式对象,适合用来定义包含多个属性的复杂状态。我们可以在组件的外部调用reactive,得到一个独立的响应式实例。
import { reactive } from 'vue'
// 创建独立的响应式实例
const sharedState = reactive({
count: 0,
userList: [],
theme: 'light'
})
// 可以直接修改实例的属性,修改会触发响应式更新
sharedState.count++
sharedState.theme = 'dark'
使用ref创建基础类型或任意类型响应式实例
ref函数可以处理基础类型数据,也可以处理对象类型数据,返回的是一个包含value属性的响应式引用对象,使用起来更加灵活。
import { ref } from 'vue'
// 创建基础类型的独立响应式实例
const globalLoading = ref(false)
// 创建对象类型的独立响应式实例
const appConfig = ref({
apiBaseUrl: 'https://ipipp.com/api',
timeout: 5000
})
// 修改值需要通过value属性
globalLoading.value = true
appConfig.value.timeout = 10000
独立响应式实例的应用场景
跨组件共享状态
当多个组件需要访问和修改同一份状态时,不需要通过props逐级传递或者使用事件总线,直接导入独立的响应式实例即可实现状态共享。
// store/sharedState.js
import { reactive } from 'vue'
export const userState = reactive({
userInfo: null,
isLogin: false
})
// ComponentA.vue
import { userState } from './store/sharedState.js'
export default {
setup() {
const login = () => {
userState.isLogin = true
userState.userInfo = { name: 'test', age: 20 }
}
return { userState, login }
}
}
// ComponentB.vue
import { userState } from './store/sharedState.js'
export default {
setup() {
return { userState }
}
}
封装通用工具函数
我们可以将独立的响应式实例和对应的操作方法封装在一起,形成通用的工具模块,在项目中直接复用。
import { ref } from 'vue'
// 封装请求状态的响应式工具
export function useRequestState() {
const loading = ref(false)
const error = ref(null)
const data = ref(null)
const resetState = () => {
loading.value = false
error.value = null
data.value = null
}
return {
loading,
error,
data,
resetState
}
}
// 在组件中使用
import { useRequestState } from './utils/requestState.js'
export default {
setup() {
const { loading, data, resetState } = useRequestState()
// 发起请求时修改状态
return { loading, data, resetState }
}
}
注意事项
- 独立响应式实例如果是用reactive创建的,不要直接替换整个对象,否则会丢失响应式,比如不要写sharedState = { count: 1 },应该修改内部属性。
- ref创建的响应式实例,修改值时一定要通过value属性,在模板中使用时会自动解包,不需要写value。
- 独立响应式实例的状态修改不会被Vue的开发者工具自动追踪到组件层级,排查问题时需要注意状态的来源。
两种创建方式的对比
| 对比项 | reactive | ref |
|---|---|---|
| 适用数据类型 | 仅对象类型 | 基础类型、对象类型均可 |
| 访问方式 | 直接访问属性 | 通过value属性访问 |
| 重新赋值影响 | 直接替换对象会丢失响应式 | 重新赋值给value不会丢失响应式 |
| 模板中使用 | 直接使用属性名 | 自动解包,不需要写value |