简体   繁体   中英

@ngrx/effects gives TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable

I have a scenario where I need to sequence two @Ngrx actions in my Angular application.

The first action updates the state with some data, and the second action uses that data to trigger a server call. I am using an Effect to sequence the two actions and trigger the second action only after the first one has completed.

To ensure the second action includes the recently updated data from the state, I inject the store into my effect and use a selector function to retrieve the data and include it as the payload for the second action.

This works.

My Question

However, I believe that since the this.actions$ is already an observable stream, I should be able to simply transform each event on that stream and convert that into a different action.

A rough marble diagram of what I have in mind: 粗略的想法

I am using the withLatestFrom operator to combine the action stream with the data from the state.

  @Effect()
  lazyEffect1$ = this.actions$.ofType(LazyActions.TEST_ACTION_SEQUENCE)
     .withLatestFrom(this.filterId$, (x, y) => {
       return new LazyActionDone(y.number);
     });

But this code gives me an error:

TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.

I have been able to get this to work using a slightly different construct, which is also included in the code below.

But I would like to understand why the lazyEffect1 is not working. Where is my understanding failing me?

The Code

The NgRx Reducer:

// reducers.ts
export function lazyReducer(
  state: any = {},
  action: LazyAction | LazyActionDone
) {

  switch (action.type) {
    case LazyActions.TEST_ACTION_SEQUENCE: {
      console.info('Action Received in Reducer: ', action.type);
      return {
        ...state,
        number: action.payload
      };
    }

    case LazyActions.TEST_ACTION_SEQUENCE_DONE: {
      console.info('Done Received in Reducer: ', action.type);
      return {
        ...state,
        retrieved: action.payload,
        done: true
      };
    }

    default: {
      return state;
    }
  }
}

The NgRx Effects:

// effects.ts
@Injectable()
export class LazyEffects {
  private filterId$: Observable<any>;

  constructor(
    private actions$: Actions,
    private store: Store<any>
  ) {
    this.filterId$ = this.store.select(getLazyState);
  }

  // THIS DOES NOT WORK
  @Effect()
  lazyEffect1$ = this.actions$.ofType(LazyActions.TEST_ACTION_SEQUENCE)
     .withLatestFrom(this.filterId$, (x, y) => {
       // console.info(x, y);
       return new LazyActionDone(y.number);
     });

  // THIS WORKS
  @Effect()
  lazyEffect2$ = this.actions$.ofType(LazyActions.TEST_ACTION_SEQUENCE)
    .switchMap((action) => {
      console.info('Action Received in Effects: ', action.type);
      return of(action).withLatestFrom(this.filterId$, (x, y) => new LazyActionDone(y.number));
    });
}

Just to spell out the solution @cartant provided ..I believe the solution is to replace this property:

  // THIS DOES NOT WORK
  @Effect()
  lazyEffect1$ = this.actions$.ofType(LazyActions.TEST_ACTION_SEQUENCE)
     .withLatestFrom(this.filterId$, (x, y) => {
       // console.info(x, y);
       return new LazyActionDone(y.number);
     });

With this function:

  @Effect()
  lazyEffect1$() { 
     return this.actions$.ofType(LazyActions.TEST_ACTION_SEQUENCE)
     .withLatestFrom(this.filterId$, (x, y) => {
       // console.info(x, y);
       return new LazyActionDone(y.number);
     });
   }

@cartant deserves the credit for his answer in the comments, but I want to provide an answer/example for anyone else who comes across this issue and doesn't notice that the answer is in the comments.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

Related Question TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable ERROR TypeError: You provided 'null' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable Rxjs 6: using catchError() gives You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable Angular5 : TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable. at <Jasmine> TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable when deploying angular ERROR TypeError: You provided 'undefined' where a stream was expected. You can provide an Observable, Promise, Array, or Iterable in Angular Services Angular: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM