Open Xylez01 opened 4 years ago
Hey, could you share your fix? im having the same issue and i think vuex-persisted storage also has this issue, cheers!
Sure, although I'm thinking recently to drop it again, as we had few issues with it in the past.
The core of the solution is this:
const typesThatShouldBeRestored: any[] = []
const classNameProperty = '__className'
// Use this to decorate a class that needs to be restored
export function Restore() {
return function _Restore<T extends { new (...args: any[]): {} }>(constructor: T) {
typesThatShouldBeRestored.push(constructor)
return class extends constructor {
constructor(...args: any[]) {
super(...args)
// @ts-ignore
this[classNameProperty] = constructor.name
}
}
}
}
function canBeRestored(object: any): boolean {
return object.hasOwnProperty(classNameProperty)
}
// Use this method to restore the typing on an object
export function restoreTyping(object: AppState | any) {
if (isArray(object)) {
object.forEach(item => restoreTyping(item))
}
for (const property in object) {
if (!object.hasOwnProperty(property)) {
continue
}
const targetObject = object[property]
if (isObject(targetObject)) {
if (canBeRestored(targetObject)) {
const type = typesThatShouldBeRestored.find(
// @ts-ignore
instanceType => instanceType.name === targetObject[classNameProperty]
)
object[property] = Object.assign(Object.create(type!.prototype), targetObject)
} else {
restoreTyping(targetObject)
}
}
}
}
Decorate all classes that need to be restored like this:
@Restore()
export class MyDataHoldingClassInStorage { ... }
And lastly, modify the restore state method of the vuex persist:
new VuexPersist({
...
restoreState: (key, storage) => {
let json = storage!.getItem(key) as string
if (isEmpty(json)) {
json = '{}'
}
try {
const state = JSON.parse(json)
restoreTyping(state)
return state
} catch {
return {}
}
}
})
I managed it by just accessing the Getter instead of the state directly and in the getter cast it to my class object
Store
const CartStore: Module<CartStoreState, any> = {
namespaced: true,
state: {
cart: new Cart(),
},
getters: {
getCart: (state): Cart => {
if (state.cart instanceof Cart) {
return state.cart;
}
return Object.assign(new Cart(), state.cart);
},
},
Vue Component
const cartStore = namespace("cart");
@Component
export default class ProductCardColumn extends ProductCardColumnProps {
@cartStore.Getter("getCart") cart;
Right now when using for example
localStorage
objects that are classes (and not interfaces) are not properly restored. Any properties or methods will not exist. Are there any plans to support this?We've created our own implementation for our project (using type decorators), willing to share and propose a solution/implementation if you are interrested.