记录一下本人工作中遇到的一些问题,以及解决思路
背景
本人设计项目设计之初,状态管理最开始使用pina
但是pina更适合作为一种全局的状态管理方式。
面对以下场景时可能不太合适:
-
1、涉及到不同实例间的切换: 本项目中:不同的案件共用一个pina都store, 可能会面对不同案件之间相互污染数据的情况: 在激活案件a时,store此时存储着案件a的数据,这时候如果发起一个请求a,这个请求a会涉及到改变store中的状态。在请求a还未返回时,切换至案件b,此时store要切换至存储案件b的数据,这样一来,当请求a返回时,带来的是案件a的数据,就会污染此时存储着案件b的store。
-
2、每个案件存储的数据量其实比较庞大,理论上,只需要这工作空间这一个模块需要这些响应式数据,切换至别的模块时,这些数据应该清理。
尽管可以在pina中手动设置reset,来清理数据。但事实上,如果涉及到的状态变量太多,难免没有清理干净,带来内存方面的压力,尽管在页面上影响不大。但这不利于后续的维护,设计上可以再优化下
解决方式:
一、作用域单例:
有点类似于react的设计,具体实方法如下
实现方式: 1、创建一个工厂函数,里面包含模块内部所需要的所有状态和方法
export function useMaterialProcess() {
const currentID = ref<string | null>(null);
const currentStatus = ref<number>(0);
...
return {
currentID,
currentStatus
}
}
2、封装Provider组件
2.1: symbol确保唯一key + 封装注入hook
import type { InjectionKey } from 'vue'
import { inject } from 'vue'
import { useMaterialProcess } from './useMaterialProcess'
export type MaterialProcessContext = ReturnType<typeof useMaterialProcess>
// symbol确保唯一key
export const materialProcessKey: InjectionKey<MaterialProcessContext> = Symbol('MaterialProcess')
export function useMaterialProcessInject() {
const ctx = inject(materialProcessKey)
if (!ctx) {
throw new Error('useMaterialProcessInject must be used inside <MaterialProcessProvider>')
}
return ctx
}
2.2: Provider组件,负责创建一次实例 & Provider
这样可以确保:
a) ctx只会创建一次, 组件存在期间就是单例
b) 组件卸载 即为 自动释放
<script setup lang="ts">
import { provide, onUnmounted } from 'vue'
import { materialProcessKey } from './materialProcessContext'
import { useMaterialProcess } from './useMaterialProcess'
const ctx = useMaterialProcess()
provide(materialProcessKey, ctx)
onUnmounted(() => {
// 处理回收逻辑
})
</script>
<template>
<slot />
</template>
2.3 使用方式:
模块最外层包裹一层provider:
通过 key 确保每次切换新的case,都会更新,不会造成实例的污染
<template>
<MaterialProcessProvider :key="caseId">
<OutestModule />
</MaterialProcessProvider>
</template>
<script setup lang="ts">
import MaterialProcessProvider from './composables/MaterialProcessProvider.vue';
</script>
综上,通过以上方式,可从根本上解决本项目使用pina所带来的问题