Can we Memoization a object from the ngrx store? I mean, I can memoization a simple primitive value but lets say I want to memoization an object/array.
**REDCUER**
export const initialState: AuthState = {
isAutenticated: false,
msg: ""
};
const reducer = createReducer(
initialState,
on(isAuths, (state: AuthState, action) =>({ ...state })),
on(isAuthChanged, (state: AuthState, action) => {
return {
...state,
isAutenticated: action.isAutenticated
}
})
);
**SELECTORS**
export const selectAuth = (state: AppState) => state.auth
export const selectAuthState = createSelector(
selectAuth,
(state: AuthState) => state <------------ NO MEMORIZATION
);
export interface AuthState {
isAutenticated: boolean;
msg: string;
}
for example INITAL STATE: {isAutenticated: false, msg: ""}
And:
this.store.select(selectAuthState)
.subscribe(r=>console.log(r))
setTimeout(()=>
this.store.dispatch(isAuthChanged({ isAutenticated: false, msg: "" }))
,5000)
so this will be trigger First time initial value, and then with the new event after 5 sec even if its the same values {isAutenticated: false, msg: ""}. I want it to be trigger only once.
if i will do something like this:
export const selectAuthState = createSelector(
selectAuth,
(state: AuthState) => state.isAutenticated <------------ MEMORIZATION only on the state isAutenticated
);
So this will be works only on the state isAutenticated, and the subscribe function will return true or false, but i want to return the full object.
I could check for the same values in the reducer and check if they equal and then return the same state.
like this:
on(isAuthChanged, (state: AuthState, action) => {
if (state.isAutenticated == action.isAutenticated && state.msg == action.msg) {
return state;
} else {
return {
...state,
isAutenticated: action.isAutenticated
}
}
})
But I wonder if there another way to achieve this approach using selectors to memorization the whole Object?
thanks
Ngrx's select function relies on distinctUntilChanged behind the scenes. Hence, that is why returning a simple boolean (or any primitive) will work, but returning an object will trigger the selector. Remember, distinctUntilChanged will filter based on a reference equality check (i.e. object-a === object-b).
In order to achieve the memoization behavior that you want for a certain object state, you have to focus on the reducer. For example, in the reducer function for isAuthChanged, you can check whether the state object has changed by doing a deep equality check: if the object changed, return a new state, otherwise, return the same state.
For example:
on(isAuthChanged, (state: AuthState, action) => {
if (deepEqual(state, action)) {
return state;
} else {
return {
...state,
isAutenticated: action.isAutenticated
}
}
})
...
function deepEqual(a, b) {
return a.isAutenticated == a.isAutenticated && b.msg == b.msg
}
This is really no different than what you've already posted, so this answer just confirms that you're on the right track.
You can optimize this a bit, by leveraging fast-deep-equal.
For example:
on(isAuthChanged, (state: AuthState, action) => {
return equal(state, action) ?
state :
{ ...state, isAutenticated: action.isAutenticated};
})
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With