我的 pinia 商店里有一个像这样的东西
import { defineStore } from "pinia";
export const useSearchStore = defineStore("store", {
state: () => {
return {
myobj: {
foo: 0,
bar: 2000,
too: 1000,
},
};
},
getters: {
changed() {
// doesn't work
return Object.entries(this.myobj).filter(([key, value]) => value != initialvalue
);
},
},
});
如何获取初始值来测试对象是否发生变化。或者如何返回仅包含与初始状态不同的条目的过滤对象?
我目前的解决方法: 在创建的钩子中,我制作了商店对象的硬拷贝,然后可以进行比较。我想有一种更优雅的方式...
我已经这样做了(尽管我不知道是否有更好的方法来避免克隆而不重复您的初始状态)。
在外部定义初始状态并将其分配给变量,如下所示;
const initialState = {
foo: 0,
bar: 2000,
too: 1000
}
然后就可以使用克隆来保留原来的状态;
export const useSearchStore = defineStore("store", {
state: () => {
return {
myobj: structuredClone(initialState),
};
},
getters: {
changed: (state) => deepEquals(initialState, state.myobj);
},
});
其中
deepEquals
是一种深度比较两个对象的方法(您必须实现)。为此,我会使用 lodash
(如果您使用的是 TypeScript,则为 npm i lodash
和 npm i @types/lodash --save-dev
)。
完整代码(带有lodash);
import { defineStore } from "pinia";
import { cloneDeep, isEqual } from "lodash";
const initialState = {
foo: 0,
bar: 2000,
too: 1000
}
export const useSearchStore = defineStore("store", {
state: () => ({
myobj: cloneDeep(initialState)
}),
getters: {
changed(state) {
return isEqual(initialState, state.myobj);
},
},
});
如果您还想了解两者之间的差异,可以使用以下函数(
_
是lodash - import _ from "lodash"
);
function difference(object, base) {
function changes(object, base) {
return _.transform(object, function (result: object, value, key) {
if (!_.isEqual(value, base[key])) {
result[key] =
_.isObject(value) && _.isObject(base[key])
? changes(value, base[key])
: value;
}
});
}
return changes(object, base);
}
由https://gist.github.com/Yimiprod/7ee176597fef230d1451
提供编辑:
执行此操作的另一种方法是使用观察者来订阅更改。这样做的缺点是,如果您将数据改回初始状态,则必须将状态标记为“已更改”。否则,您将必须实现一个系统(可能使用堆栈数据结构)来维护更改列表,以便如果发生两个相互抵消的更改,那么您会将状态标记为“未更改”。您必须在状态中保留另一个变量(布尔值),该变量保存状态是否已更改/未更改 - 但这实现起来会更复杂并且(取决于您的用例)不值得。
有一种更简单的方法可以实现此目的,无需进行深层复制。也许我没有明白这一点(在这种情况下,请编辑您的问题以使其更准确),但我将介绍两种情况,以便我可以理解您的问题。
首先,根本不需要深拷贝。只需在商店中声明您的初始状态,如下所示:
const initialState {
'first':'sampleOne',
'second':'sampleTwo'
}
您只需将其传播到您所在的州即可用初始状态填充您的商店。为了简单起见,我省略了操作和设置器。
export const useExampleStore = defineStore('example', {
state: () => ({
...initialState
}),
});
如果您想知道数据何时发生变化,您现在可以在组件或 App.vue 文件中编写一个观察器,每次数据发生变化时都会触发该观察器。如果数据是反应性的(例如,您使用 storeToRefs(useStore())),您只需要记住让您的观察者成为深度观察者。
watch(
() => first.value,
(newValue, oldValue) => {
// Note: `newValue` will be equal to `oldValue` here
// *unless* state.someObject has been replaced
},
{ deep: true }
)
但是,如果您必须将其他数据与商店的初始状态进行比较,那么将初始数据的第二个实例存储在商店本身中可能是一个好主意,或者如果您想将其进一步分离,您可以编写一个全新的存储,其中仅包含数据并且不会受到干扰。
export const useExampleStore = defineStore('example', {
state: () => ({
data: ...initialState,
referenceData: ...initialState
}),
});
这样您就可以处理您的数据,而且还可以有一个对象来比较它。
您真的需要拥有初始数据、使用它、比较它、再次操作它并再次比较吗?也许你可以更清楚,为什么你需要这样做,或者用例到底是什么,因为我认为,还有更多、也许更简单/更好的方法来实现这一点。