Vue3无需依赖Pinia实现父亲、儿子、孙子组件共享状态

135 阅读2分钟

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值可能会引起数据流混乱,导致维护困难。因此,在使用这种方法共享状态时要确保不随意修改状态。