pass data from state to new action in rxjs effect

Viewed 45

I want to access state data to pass the results as properties of a new action. I managed to extract the required data from the state after the effect is triggered but the final part dispatching the new action using data isn´t working. I can´t pass the two arguments activeUser and activeTask to the of(GetInstances({activeUser, activeTask})) part in the last line of code.

@Effect()
updateInstanceLabelSuccess$ = this._actions$.pipe(
  ofType<Action>(EInstanceActions.UpdateInstanceLabelSuccess),
  concatMap(action => of(action).pipe(
    withLatestFrom(combineLatest(
      [this._userStore.pipe(select(selectActiveUser)),
        this._userStore.pipe(select(selectActiveTask))]
    ))
  )),
  tap(([action, [activeUser, activeTask]]: [Action, [User, Task]]) => {
    console.log(activeUser, activeTask);
    // activeUer and activeTask successfully loaded
    // pass activeUser + activeTask to props of Action GetInstances
  }),
  // activeUser and activeTask can´t be passed to new GetInstances Action
  switchMap(([action, [activeUser, activeTask]]: [Action, [User, Task]]) => of(GetInstances({activeUser, activeTask})))
);

How is it possible to pass the two parameters activeUser and activeTask to a new GetInstances Action?

EDIT:

I got it working with the following code. Is this a valid solution for the problem?

@Effect()
updateInstanceLabelSuccess$ = this._actions$.pipe(
  ofType<Action>(EInstanceActions.UpdateInstanceLabelSuccess),
  concatMap(action => of(action).pipe(
    withLatestFrom(combineLatest(
      [this._userStore.pipe(select(selectActiveUser)),
      this._userStore.pipe(select(selectActiveTask))]
    ))
  )),
  map(([action, [activeUser, activeTask]]: [Action, [User, Task]]) => GetInstances({userID: activeUser.id, taskID: activeTask.id}))
);
1 Answers

That code looks great, and is a perfectly valid way to do it.

Unless I'm missing something, I think you could clean things up like:

@Effect()
updateInstanceLabelSuccess$ = this._actions$.pipe(
    ofType<Action>(EInstanceActions.UpdateInstanceLabelSuccess),
    withLatestFrom(
        this._userStore.pipe(select(selectActiveUser)),
        this._userStore.pipe(select(selectActiveTask)),
        (action, activeUser, activeTask) => [activeUser, activeTask]
    ),
    map(([activeUser, activeTask]): [User, Task]) => GetInstances({userID: activeUser.id, taskID: activeTask.id}))
);

All I'm doing here is taking advantage of the overloads of withLatestFrom, including a final projection function, which I find useful in these situations where you don't want to carry around the extraneous Action.

Another suggestion is to create a new selector that combines those 2 you have. I know that sounds like overkill, but doing it that way gives you a small performance advantage due to the built-in caching of selector results.

Anyway, I hope that helps. Nice work on figuring that out.

Related