Issue
I am developing an Ionic Application with Angular and i want that if the user refreshes the page, the state of the app before the refresh gets loaded again. For state management i am using NgRx. The problem is that everytime I reload my page the state gets reset into the initialState of the App.
So i save the state to the localstorage everytime it changes with the following code inside the onInit function of my app.component.ts:
this.store.subscribe(state => {
localStorage.setItem('appState', JSON.stringify(state))
})
This works just fine and when i check the localstorage of my browser there is the right data inside of it.
To then retrieve the state after the reload i use this initializer function chatGPT recommended to me:
export function appInitializer(store: Store<AppState>): () => Promise<void> {
return (): Promise<void> => {
return new Promise<void>((resolve) => {
const savedState = localStorage.getItem('appState');
if (savedState) {
let state: AppState = JSON.parse(savedState);
console.log(state);
store.dispatch(setState({state}));
}
resolve();
});
};
}
This is called correctly, i know that because of the console.log which also always logs the data i want to set my store to.
So then my only problem should be the "setState" action(which i know gets called because I am using NgRx Devtools)Devtools Screenshot of my store right? It looks like this:
actions.ts:
export const setState = createAction("[App] setState", props<{state:AppState}>());
reducers.ts:
const initialState: AppState = AppInitialState;
const reducer = createReducer(initialState,
on(setState, (currentState, action) => {
return {
...currentState,
loading:{
show: action.state.loading.show,
},
login: {
error: action.state.login.error,
isLoggedIn: action.state.login.isLoggedIn,
isLoggingIn: action.state.login.isLoggingIn
}
}
})
)
export function mainReducer(state:AppState, action: Action){
return reducer(state, action);
}
AppState.ts:
export interface AppState {
loading:LoadingState;
login: LoginState;
}
LoadingState.ts:
export interface LoadingState{
show: boolean;
}
LoginState.ts:
export interface LoginState{
isLoggingIn: boolean;
isLoggedIn: boolean;
error: any;
}
Does someone know where I made the mistake?
Solution
The idea behind it is good and the correct way, but the implementation needs to be tweaked a bit.
This is a great use case for a meta-reducer to set the state into the desired state. You can also take a look at https://github.com/btroncone/ngrx-store-localstorage instead of writing this logic yourselves.
https://timdeschryver.dev/blog/ngrx-flush-state has an example to clean the store's state, but the idea is the same. Instead of clearing it you can populate it with the desired state that's added to the action.
Answered By - timdeschryver
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.