Vue3无需依赖Pinia实现父亲、儿子、孙子组件共享状态
在Vue中如果父组件有一份状态需要被儿子和孙子一起使用,处理起来往往很麻烦。如果我们给每一个儿子和孙子都写一个props一层层传递,未免也太麻烦了。如果我们使用pinia好像又有点大材小用了,因为这个状态只在这一个父亲、儿子以及孙子中使用,其他的组件可能并不需要。
其实,实现一份共享的状态很简单。
我们创建一个context.ts文件。
这个文件是一个简单的管理计数器的共享状态实现。我们将响应式数据(状态)全部写在useCount函数的外部。利用JS的闭包机制,保证每个组件调用useCount函数时,得到的count都是同一个引用。然后我们可以将对count的操作都写在useCount中和count一起返回出去。这样的话,我们不论在父亲组件,儿子组件,孙子组件中都可以渲染count,并且对count进行操作。
import { ref } from 'vue'
const count = ref(0)
export function useCount() {
function increment() {
count.value++
}
function decrement() {
count.value--
}
return {
count,
increment,
decrement
}
}
APP.vue
<script setup lang="ts">
import ContextDemo from './views/ContextDemo/index.vue'
import { useCount } from './views/ContextDemo/context'
const { count, decrement,increment } = useCount()
</script>
<template>
<div>
<ContextDemo />
<div>APP - count : {{ count }}</div>
<button @click="increment">increment</button>
<button @click="decrement">decrement</button>
</div>
</template>
<style scoped></style>
index.vue即ContextDemo
<script setup lang="ts">
import Son from './Son.vue';
defineOptions({
name: 'index'
})
</script>
<template>
<div>
<Son/>
</div>
</template>
<style scoped>
</style>
Son.vue
<script setup lang="ts">
import GrandSon from './GrandSon.vue'
import { useCount } from './context'
defineOptions({
name: 'Son',
})
const { count } = useCount()
</script>
<template>
<GrandSon />
<div>Son-count : {{ count }}</div>
</template>
<style scoped></style>
GrandSon.vue
<script setup lang="ts">
import { useCount } from './context'
defineOptions({
name: 'GrandSon'
})
const { count } = useCount()
</script>
<template>
<div>
GrandSon-count : {{ count }}
</div>
</template>
<style scoped>
</style>
可以看到,通过闭包机制,我们的每一个组件都可以使用同一份状态。但是,我们应该确保使用useCount中定义的方法去修改count值。因为随意修改count值可能会引起数据流混乱,导致维护困难。因此,在使用这种方法共享状态时要确保不随意修改状态。