Reputation: 2107
To get persistent user information across components I'm trying to implement NgRx store into my solution but have come stuck with getting the data from the store using selectors.
The error that comes back through the console is that user (part of the AuthState) is undefined but when logging in I pass it to the store and can see it when expanding source multiple times.
I've been following the documentation https://www.npmjs.com/package/ngrx-store-localstorage but am now a bit stuck, any suggestions on how to proceed or debug this effectively would be welcome.
Component
this.store.dispatch(addUser({ data: userDetails }));
Action
export const addUser = createAction(
'[Auth] Add user',
props<{ data: LoggedUserDetails }>()
);
export const loadUser = createAction(
'[Auth] Load user'
);
Reducer
export const initialAuthState: AuthState = {
user: {
email: '',
accessToken: '',
idToken: '',
name: '',
id: ''
},
authenticated: false
};
// handles the retrieval of the user details
export const authReducer = createReducer(
initialAuthState,
on(addUser, (state, { data }) => ({
...state,
user: data,
authenticated: true
})),
on(loadUser, (state) => ({
...state,
user: state.user,
authenticated: state.authenticated
}))
);
Selector
export const selectAuthState = (state: AppState) => state.authState;
export const selectUserDetails = createSelector(
selectAuthState,
(authState: AuthState) => authState.user);
Module
export function localStorageSyncReducer(
reducer: ActionReducer<any>
): ActionReducer<any> {
return localStorageSync({ keys: ['auth'], rehydrate: true })(reducer);
}
const metaReducers: Array<MetaReducer<any, any>> = [localStorageSyncReducer];
// within the imports rather than copying the entire module
StoreModule.forRoot(
authReducer, { metaReducers }
)
shared component
this.store.pipe(select(selectUserDetails)).subscribe((res: LoggedUserDetails) => {
// accessing from a shared component this gives the user is undefined error
this.userDetails = res;
});
Upvotes: 0
Views: 1493
Reputation: 3393
Selectors fire on every state change. Consequently I would guess your selector fires before the user state is initialized - it will fire again when you set the user state.
You can prevent the error by using the ?.
operator:
export const selectUserDetails = createSelector(
selectAuthState,
(authState: AuthState) => authState?.user;
Also your on
in the reducer for loadUser
sets the state to the same values it already had, so is redundant.
Upvotes: 2