Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Twitter-like app with Angular2 ngrx. Structuring AppState

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:

  • Home page - either with registration/login form or with random citation (if signed in).
  • Profile page with tabs
    • Tab with all citations published by the user and a form to publish a new one.
    • Profile info
  • Citations feed page
  • Page to view other user's profile with similar structure as above. (when user clicks on the citation's publisher).

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:

  1. AuthState
  2. UserState
  3. UserListState
  4. CitationState
  5. CitationListState

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
  
  //.....
}
like image 438
Daniil Andreyevich Baunov Avatar asked Jul 04 '26 17:07

Daniil Andreyevich Baunov


1 Answers

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
           };
     });
like image 91
cgatian Avatar answered Jul 07 '26 08:07

cgatian



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!