[ ] Yes (Assistance is provided if you need help submitting a pull request)
[ ] No
Derived data already exists in the Store, so we should add more examples of it. One example is being logged in based on the authenticated user instead of the loggedIn property in the store.
Hey @brandonroberts,
I would take over this task, if you don't mind. Could you explain a bit more in detail what you mean?
Thanks
In my understanding, derived data means the data that is calculated from State and got via selectors.
For example,
export interface State {
loggedIn: boolean;
user: User | null;
}
export const initialState: State = {
loggedIn: false,
user: null,
};
export function reducer(state = initialState, action: AuthActionsUnion): State {
switch (action.type) {
case AuthActionTypes.LoginSuccess: {
return {
...state,
loggedIn: true,
user: action.payload.user,
};
}
case AuthActionTypes.Logout: {
return initialState;
}
default: {
return state;
}
}
}
export const getLoggedIn = (state: State) => state.loggedIn;
export const getUser = (state: State) => state.user;
In this case, we get loggedIn from State.
In next case, we get loggedIn via selector as derived data.
export interface State {
user: User | null;
}
export const initialState: State = {
user: null,
};
export function reducer(state = initialState, action: AuthActionsUnion): State {
switch (action.type) {
case AuthActionTypes.LoginSuccess: {
return {
...state,
user: action.payload.user,
};
}
case AuthActionTypes.Logout: {
return initialState;
}
default: {
return state;
}
}
}
export const getLoggedIn = (state: State) => !!state.user;
export const getUser = (state: State) => state.user;
@brandonroberts @timdeschryver
Is my answer right? :smiley:
@kouMatsumoto yep, exactly!
Just one little thing I believe it should be:
// reducer.ts
export const getUser = (state: State) => state.user;
// index.ts
export const getUser = createSelector(userState, fromUsers.getUser);
export const getLoggedIn = createSelector(getUser, user => !!user);
Is the above enough for you @mgred, to get started? 馃槃
Got it @timdeschryver!
Thanks for the example @kouMatsumoto, I will have a look and keep you all updated here.
Hello!
About this, what is the NGRX team best practice for selectors on large store? I have a main reducer whose ActionReducerMap has 16 keys (so 16 features), if I put all my selectors in the main reducers.ts file, it would have more than 1000 LOC. Currently, I have a my-feature.selectors.ts file in each that import the substate selector from reducers.ts. But I find it a bit weird...
Example usage of my current solution:
books/books.selectors.ts
import { createSelector } from '@ngrx/store';
import { selectBooksState } from '../index';
import * as fromBooks from './books.reducer';
export const getSelectedBookId = createSelector(
selectBooksState,
fromBooks.getSelectedBookId
);
Hey guys,
I started the work on this and begun with the given example.
There is already a PR (#1286) that tracks everything.
In projects/example-app/src/app/auth/reducers/index.ts the linter reported of incompatible types in line 20:
export const reducers: ActionReducerMap<AuthState> = {
status: fromAuth.reducer,
loginPage: fromLoginPage.reducer,
};
I then added the AuthActionUnion type as the second type parameter to the definition:
export const reducers: ActionReducerMap<AuthState, AuthActionUnion> = {
status: fromAuth.reducer,
loginPage: fromLoginPage.reducer,
};
Even though the linter reports an error the compilation and serving of the app worked nevertheless.
Was this left off on purpose? And should that stay off?
There are some other files reporting the same _Error_.
@mgred its a known issue that's being tracked here https://github.com/ngrx/platform/issues/951. For now, we are changing it to any
@brandonroberts thanks for this advice. I will change it to any in this case.
Most helpful comment
Got it @timdeschryver!
Thanks for the example @kouMatsumoto, I will have a look and keep you all updated here.