We are using persisted localstorage state in our application.
When adding new fields or values to the store module, they are not applied to existing users' states. It only works when clearing the storage.
How should one go about solving this issue?
One possible solution I have thought of is following:
Is it a viable option or are there better ways of handling this issue?
Without getting much into implementation details you should merge the localStorage state with the existing vuex state like this:
export const mutations: MutationTree<YourState> = {
MERGE_USER_STATE(state, userState: Partial<YourState>) {
state = {...state, ...userState};
}
}
This will extend your existing state with a previous state cached inside the users localStorage. Existing keys will be overriden while new keys are preserved.
This has a few drawbacks though:
A better way would be to use a versioning mechanism and handle the transformation yourself. That way you have knowledge about the schema stored inside the user's localstorage and can transform that schema into anything you want.
Given a user with a localstorage state
item containing:
{
version: 1,
data: {
favoriteAnimals: ["Dog", "Cat"]
}
}
And given a vuex store that allows users to add/edit their favorite animals:
export const state = () => {
version: 1,
favoriteAnimals: []
}
export const mutations = {
ADD_ANIMAL(state, animal: string){
state.favoriteAnimals.push(animal);
localStorage.setItem('state', JSON.stringify({
version: state.version,
data: state
})
)
},
// more mutations to remove and whatnot
}
export const actions = {
add(context, animal: string){
commit("ADD_ANIMAL", animal);
},
load(context, userState: string){ // userState = localStorage state
const {version, data} = JSON.parse(state);
// for now we don't care about data. we assume data is an array of strings
data.forEach(animal => commit("ADD_ANIMAL", animal);
}
}
Now a few weeks in your team decides to change the list of favorite animals from a list of strings into a list of objects like this:
[ { animal: "Dog", ranking: 5 } ]
Obviously when the user visits with his old localstorage your app will break as the types are incompatible now.
You can now edit your load
action like this:
load(context, userState: string){ // userState = localStorage state
const {version, data} = JSON.parse(state);
if (version === 1){ // old user detected.
data.forEach(animal => {
commit("ADD_ANIMAL", { name: animal, ranking: 0 });
});
return;
}
// default action when the version is up to date
data.forEach(animal => commit("ADD_ANIMAL", animal);
}
At a certain scale this will grow into a bigger and bigger function although I think it's fine as it's easy to extend. You can always add analytics and track which version your users are actually on. This also has the added benefit that the state of each user gets updated automatically whenever they open the app as vuex will update the state accordingly after commiting to it's internal state.