前置知识
一个组件,外部的数据放在props里面内部的数据可以放在ref/reactive里。
两个组件情况会比较复杂。
第一种情况:父子关系
子组件会通过props来获得父组件的一些属性,这个子组件也拥有自己的ref/reactive
假设现在有一个数据叫做currentUser,很多组件都需要用到这个数据。如何实现呢。 我们很容易想到:父组件向服务器请求currentUser,放到ref里面,子组件也去请求currentUser也放到自己的ref了里面。从逻辑上是没有任何问题的。 但是这样会造成一些后果:
- 请求太多了
- 数据冗余
所以基本不使用这种办法,我们选择的思路是复用
实现办法:让父组件向服务器请求currentUser,拿到数据后放在自己的ref/reactive里面。父组件可以对其进行读和写的操作。子组件可以通过props来得到这个数据,但是是只读的,如果想修改只能
context.emit('update:currentUser,user2)这种形式。把user2赋值到currentUser上。
第二种情况:爷孙关系
中间隔了一代,不能直接通过props实现爷组件向孙组件的数据通信,只能先传输给父组件再传给孙组件。很显然这样做是不好的。
所以在Vue中跨组件通信需要依赖注入 在爷组件处进行provide,在孙组件处进行inject。
第三种情况:兄弟关系
有两个并列关系的兄弟组件,都需要用到currentUser数据。这种情况,按照常规思路就是借助他们两个组件的父组件先请求currentUser然后分别通过props给这两个兄弟组件。
第四种情况:远方亲戚关系
实现1和2两个组件读取currentUser,依然是依赖注入方法。
在parent组件中进行provide,随后在1组件和2组件进行inject即可。
以上思路也是Vue和React的通用思路。
Vue专属思路
假设组件是如图所示的树形,如果想实现任意两个组件共享变量都是很容易的。假设他们都需要用到me这个数据,只需要将其命名为me.js然后
export const me = ref({name:xxx,id:yyy})
在需要使用me的组件中 import {me}即可。都可以对me进行读写。
所以对于任何需要共用的属性,可以导出一个全局的store
export cosnt store = reactive({
me:{},
tags:{},
})
任何组件想用store直接import即可。
全局状态管理工具——Pinia
为什么使用Pinia
Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。 如果您熟悉 Composition API,您可能会认为您已经可以通过一个简单的
export const state = reactive({}). 这对于单页应用程序来说是正确的,但如果它是服务器端呈现的,会使您的应用程序暴露于安全漏洞。 但即使在小型单页应用程序中,您也可以从使用 Pinia 中获得很多好处:
- dev-tools 支持
- 跟踪动作、突变的时间线
- Store 出现在使用它们的组件中
- time travel 和 更容易的调试
- 热模块更换
- 在不重新加载页面的情况下修改您的 Store
- 在开发时保持任何现有状态
- 插件:使用插件扩展 Pinia 功能
- 为 JS 用户提供适当的 TypeScript 支持或 autocompletion
- 服务器端渲染支持
Pinia解决了跨请求状态污染的问题
使用Pinia
定义Store的方法,声明的store必须以use开头
const useStore = =defineStore('store',{
state(){
return {
//存放数据
me:{
name:Origami
}
}
},
actions:{
//操作
refrtchMe(){
this.me.name = 'xxx'
ajax().then(()=>{
this.me
})
}
}
})
在此之前要先配置App
封装useMeStore
使用Pinia封装一个存放me的store代替之前的me.tsx
然后在用到me的地方进行替换即可。
使用storeToRefs
为了解构赋值可以使用storeToRefs 解构之后的东西就是响应式的。
封装useItemStore
ItemSummary组件中里面的数据都是用ref作为容器。由此我们可以封装一个useItemStore。
state放置数据
actions放置方法:
在ItemSummary中引入,并修改对应的变量名。
Pinia的ID固定——共享数据 Pinia的ID不固定——如果相等就共享,反之亦然