How to get the correct slice data using selectors

2019-08-18 11:12发布

问题:

I am going to create an application using angular 6 and ngrx v6. I have created the following app state.

app.module.ts

  StoreModule.forRoot({'user': userReducer, 'events': eventsReducer}),

app.state.ts

import { UsersState } from '@app/reducers/users.reducers';
import { EventsState } from '@app/reducers/events.reducers';

export interface AppState{
    user:UsersState,
    events:EventsState
}

users.reducers.ts

export interface UsersState {
    lastInteractionTime: number,
    bookmarksId: object
}

const intialState: UsersState = {
    lastInteractionTime: time,
    bookmarksId: {}
}

export function userReducer(state = intialState, action: usersActions.Action): UsersState{
  switch (action.type) {
    case usersActions.LOAD_USERS:{
      return Object.assign({}, action.payload, state);
      // return action.payload;
    }
    default:{
      return state;
    }
  }
}

events.reducers.ts

import { AppState } from '@app/app-state';

export interface EventsState {
  data: Array<Object>;
}

const intialState: EventsState = {
  lastInteractionTime: time,
  data: []
}


export function eventsReducer(state = intialState, action: eventsActions.Action): EventsState{
  switch (action.type) {
    case eventsAction.LOAD_EVENTS:{
      return Object.assign({}, action.payload, state);
      // return action.payload;
    }
    default:{
      return state;
    }
  }
}

export const selectUser = (state: AppState) => state.user;

export const selectEvents = (state: AppState) => state.events;

export const eventsByUser_ = createSelector(
  selectUser,
  selectEvents,
  (user, events) => {
      console.log('User: ' + JSON.stringify(user));
      /*
        add some logic, filter the data and return events by user's bookmark property.bookmark
      */
      return events.all[user.bookmarksId];
    }
)

When the application starts I dispatch the LoadUserAction action which called my API and returns user object with bookmarksId property.

AppComponent@ngOnInit()

this.userData = this.userService.getUser().subscribe(
      data => {
        this.userData = data.response;
        if(this.userData) {
          this.store.dispatch(new LoadUserAction(this.userData));
        }
      },
      err  => {
        console.log(err);
      }
    );

Problem: But in HomeComponent, I want to get the user's events based on their bookmarksId property. I didn't get the user's data is just because may be the API's response is not returned.

HomeComponent.ts

export class HomeComponent implements OnInit {
  constructor(private eventService:EventService) {

  }
}
ngOnInit() {
  this.eventService.getData(
    data => {
       this.store.dispatch(loadEventData(data));
    },
    err  => {
      console.log(err);
    }
  );
  this.store.pipe(select(eventsByUser_)).subscribe(
    console.log // it consoles the empty as because the user is always returning initial state with bookmarksId as empty object {}.
  )
}

EventService.ts

getData(){
  ...
  return eventsData //Observable of data.
}

Do I need to place the subscribe method "eventsByUser_" somewhere else? How can I ensure that the "eventsByUser_" selector is working only when the user slice has data.