Vue Pinia Store - 如何获取初始状态?

问题描述 投票:0回答:2

我的 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
      );
    },
  },
});

如何获取初始值来测试对象是否发生变化。或者如何返回仅包含与初始状态不同的条目的过滤对象?

我目前的解决方法: 在创建的钩子中,我制作了商店对象的硬拷贝,然后可以进行比较。我想有一种更优雅的方式...

vuejs3 pinia
2个回答
0
投票

我已经这样做了(尽管我不知道是否有更好的方法来避免克隆而不重复您的初始状态)。

在外部定义初始状态并将其分配给变量,如下所示;

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

提供

编辑:

执行此操作的另一种方法是使用观察者来订阅更改。这样做的缺点是,如果您将数据改回初始状态,则必须将状态标记为“已更改”。否则,您将必须实现一个系统(可能使用堆栈数据结构)来维护更改列表,以便如果发生两个相互抵消的更改,那么您会将状态标记为“未更改”。您必须在状态中保留另一个变量(布尔值),该变量保存状态是否已更改/未更改 - 但这实现起来会更复杂并且(取决于您的用例)不值得。


0
投票

有一种更简单的方法可以实现此目的,无需进行深层复制。也许我没有明白这一点(在这种情况下,请编辑您的问题以使其更准确),但我将介绍两种情况,以便我可以理解您的问题。

  1. 你只是想知道商店中的数据是否发生了变化
  2. 您必须明确地将数据与初始状态进行比较

首先,根本不需要深拷贝。只需在商店中声明您的初始状态,如下所示:

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
  }),
});

这样您就可以处理您的数据,而且还可以有一个对象来比较它。

您真的需要拥有初始数据、使用它、比较它、再次操作它并再次比较吗?也许你可以更清楚,为什么你需要这样做,或者用例到底是什么,因为我认为,还有更多、也许更简单/更好的方法来实现这一点。

© www.soinside.com 2019 - 2024. All rights reserved.