I've been looking at the ngrx and redux pattern lately and am thinking how would I rewrite my existing Angular2 app into using ngrx/store. What I have is an app where users can view and (if signed in) can like and publish citations. A typical citation object looks like this:
{
text: "Success is the ability to go from one failure to another with no loss of enthusiasm.",
publisher: user12345,
rank: 14,
//some more data
}
Application strucure looks like the following:
So, I'm quite frustrated of how would the AppState tree look like.
AppState {
UserState {
UserCitationsState,
UserInfoState,
AuthState
},
RouterState,
UserPageState //State representing the other user's page viewed
//etc
}
The main question is - what should I store in each state since all the data is fetched per-request from the backend REST api. Would it be just boolean values like e.g.:
UserPageState {
loading: false,
loaded: true
}
or should it also store all the information and just replace it every time a new user page is requested? As every time user navigates to some other's user page all the data is fetched from the backend. That's the point of fundamental confusion for me - how to handle these kind of apps with redux.
EDIT At the moment I limited myself with 5 states (5 reducers) to represent the overall app:
However, in the overall app state I'm duplicating many of them. I guess it's fine. Or would there be an even better way?
export interface AppState
{
localUser: AuthState
//homePage
homeCitation: CitationState
//profilePage
profileInfo: UserState
profileCitations: CitationListState
favouriteCitations: CitationListState
subscribers: UserListState
//userPage (when local user navigates to citation publisher's profile)
userInfo: UserState
userCitations: CitationListState
userSubscribers: UserListState
//feedPage
feed: CitationListState
//.....
}
My initial thoughts on this to think of the application state much like you would a database.
I would structure using the following reducers:
AppState: {
CitationState
UserProfileState,
UserInfo,
RouterState
}
interface CitationState {
citations: Citation[]
}
interface UserProfileState {
userProfiles: UserProfile[]
}
interface UserInfo {
userInfo: UserInfo
}
interface Citation {
id: number;
publisherId (userId): number;
rank: number;
text: string;
}
interface UserProfile {
userId: number;
citationIds: number[]
}
interface UserInfo {
userId: number;
authToken: string;
}
Each smart component would then compose the data as necessary to render the view. For example, you can determine if the user profile is your own, by checking to see if the routed user profile matches the one in the UserInfo reducer.
Don't be concerned about creating loading/loading in state, this is something you could derive from the state of your store. Since all the data is observable, when you query from it, you are given the latest snapshot of available data.
Instead of binding to a loading property of the store when loading a user's citations, instead build a query for that data.
For example:
let userCitation$ = state.select(appState => appState.citations)
.map(citations => {
let userCitation = citations.find(c => c.id === userId);
return {
loaded: !!userCitation,
userCitation: userCitation
};
});
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