你好同学,我是沐爸,欢迎点赞、收藏、评论和关注。
在 Vue3 中,对于简单状态,不使用 Pinia 和 Vuex,如何做状态管理?解下来我们看下如何使用 ref 和 reactive 做状态管理吧。
如果你有一部分状态需要在多个组件实例间共享,你可以使用 reactive() 来创建一个响应式对象,并将它导入到多个组件中:
// store.js
import { reactive } from 'vue'
export const store = reactive({
count: 0
})
<!-- ComponentA.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>From A: {{ store.count }}</template>
<!-- ComponentB.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>From B: {{ store.count }}</template>
现在每当 store
对象被更改时,<ComponentA>
与 <ComponentB>
都会自动更新它们的视图。现在我们有了单一的数据源。
然而,这也意味着任意一个导入了 store
的组件都可以随意修改它的状态:
<template>
<button @click="store.count++">
From B: {{ store.count }}
</button>
</template>
虽然这在简单的情况下是可行的,但从长远来看,可以被任何组件任意改变的全局状态是不太容易维护的。为了确保改变状态的逻辑像状态本身一样集中,建议在 store 上定义方法,方法的名称应该要能表达出行动的意图:
// store.js
import { reactive } from 'vue'
export const store = reactive({
count: 0,
increment() {
this.count++
}
})
<template>
<button @click="store.increment()">
From B: {{ store.count }}
</button>
</template>
除了我们这里用到的单个响应式对象作为一个 store 之外,你还可以使用其他响应式 API 例如 ref()
或是 computed()
,或是甚至通过一个组合式函数来返回一个全局状态:
import { ref } from 'vue'
// 全局状态,创建在模块作用域下
const globalCount = ref(1)
export function useCount() {
// 局部状态,每个组件都会创建
const localCount = ref(1)
return {
globalCount,
localCount
}
}
示例
示例一
Parent.vue<template>
<Child1></Child1>
<Child2></Child2>
</template>
<script setup>
import Child1 from './Child1.vue'
import Child2 from './Child2.vue'
</script>
Child1.vue
<script setup>
import { store } from './store'
function handleClick() {
store.increment()
}
</script>
<template>
<div style="border:1px solid #333;padding:20px;">
<h2>Child1.vue</h2>
<p>{{ store.count }} - {{ store.doubleCount() }}</p>
<button @click="handleClick">改变 store.count</button>
<!-- 或者 -->
<!-- <button @click="store.increment">改变 store.count</button> -->
</div>
</template>
Child2.vue
<script setup>
import { store } from './store'
</script>
<template>
<div style="border:1px solid #333;padding:20px;margin-top: 20px;">
<h2>Child2.vue</h2>
<p>{{ store.count }} - {{ store.doubleCount() }}</p>
</div>
</template>
store.js
import { reactive } from 'vue'
export const store = reactive({
count: 0,
doubleCount() {
return this.count * 2
},
increment() {
this.count++
}
})
效果预览
示例二
Parent.vue 不变。Child1.vue
<script setup>
import { useCount } from './store'
const { globalCount, localCount, doubleCount, increment, incrementGlobal } = useCount()
</script>
<template>
<div style="border:1px solid #333;padding:20px;">
<h2>Child1.vue</h2>
<p>globalCount - {{ globalCount }}</p>
<p>localCount - {{ localCount }}</p>
<p>doubleCount - {{ doubleCount }}</p>
<button @click="increment">改变 store 中的 localCount</button>
<button @click="incrementGlobal">改变 store 中的 globalCount</button>
</div>
</template>
Child2.vue
<script setup>
import { useCount } from './store'
const { globalCount, localCount, doubleCount, increment, incrementGlobal } = useCount()
</script>
<template>
<div style="border:1px solid #333;padding:20px;margin-top: 20px;">
<h2>Child2.vue</h2>
<p>globalCount - {{ globalCount }}</p>
<p>localCount - {{ localCount }}</p>
<p>doubleCount - {{ doubleCount }}</p>
<button @click="increment">改变 store 中的 localCount</button>
<button @click="incrementGlobal">改变 store 中的 globalCount</button>
</div>
</template>
store.js
import { ref, computed } from "vue";
// 全局状态,创建在模块作用域下
const globalCount = ref(0)
export function useCount() {
// 组件作用域
const localCount = ref(0)
const doubleCount = computed(() => localCount.value * 2)
// 修改组件作用域数据
function increment(n) {
localCount.value++
}
// 修改全局作用域数据
function incrementGlobal() {
globalCount.value++
}
return {
globalCount,
localCount,
doubleCount,
increment,
incrementGlobal
}
}
效果预览
好了,分享结束,谢谢点赞,下期再见。