0

I'm currently working with ngrx and nrg-entity. I wonder what the best practices are for updating the store after a successful web request if the response doesn't contain the entity object that have to be stored.

Example:

// My state
export interface State extends EntityState<Book> {}

I make a web request to create a book. From backend I only get an id of the created book. By default you create a reducer to put that new created book in your store like so:

createReducer(
  initialState,
on(BookActions.createBookSuccess, (state, { book}) =>
    bookAdapter.addOne(book, { ...state, creating: false })
  ));

I see two options to return the new book to the reducer:

  1. In the dataservice createBook() method you make a second call "GetBookById()" when you get the id of the new book and return the book object.
  2. In the createBookSuccess effect you trigger a dataservice call "GetBookById()" and return the result (to the reducer).

Is one of these options the way to move? Or is there a better way?

I hope I have been able to make my problem clear.

EDIT: I guess it's better to provide a practical example:

Actions:

export const createBook = createAction(
  '[Book] Create Book',
  props<{ book: NewBook }>()
);

export const createBookSuccess = createAction(
  '[Book] Create book Success',
  props<{ book: Book }>()
);

Effects:

createBook$ = createEffect(() =>
    this.actions$.pipe(
      ofType(AuftragActions.createBook),
      switchMap((action) =>
        this.bookDataService.createBook(action.book).pipe(
          map((response) =>
// what to do, to get the new book object from backend?
            BookActions.createBookSuccess({ book: response })
          ),
          catchError((error) =>
            of(AuftragActions.createAuftragFailure({ error }))
          )
        )
      )
    )
  );

Reducers:

on(BookActions.createBook, (state) => ({
    ...state,
    creating: true,
    error: null,
  })),

on(BookActions.createBookSuccess, (state, { auftrag }) =>
    bookAdapter.addOne(book, { ...state, creating: false })
  ),

Data service:

createBook(book: NewBook): Observable<Book> {
 // returns book id
}

loadByBookId(bookId: string): Observable<Book> {
 // returns book;

So, how to extend the effect "createBook$" to emit the createBookSuccess-Action with the new created book from backend?

Mossos
  • 97
  • 1
  • 11
  • Normally the flow would be: action => effect => service call => success or fail action => reducer. In other words, use effects to make calls to the server. – MikeOne Aug 29 '22 at 15:41

1 Answers1

0

There are a lot of ways you can do this but my instinct would be to have the effect trigger another action/effect that gets and sets the next value. So your first effect returns something like this,

return [
  ...,  //Whatever it already returns
  LoadBookByIdEffect
]

Then your LoadBookIdEffect triggers an Action that sets the book value in state,

return SetBook({ book });

Here is a more detailed explanation of the syntax for chaining effects together like this,

Chain Actions in an Effect in @ngrx

David Kidwell
  • 600
  • 1
  • 6
  • 15
  • Hi David, thank you for your answer! I guess I can't call an Effect within an Effect. Should I create a new Action that triggers the new LoadBookByIdEffect? I edited my question to make it more concrete. The threat of your link is four years old and it looks like the syntax of the Effects have changed.. – Mossos Aug 31 '22 at 09:07
  • Yes that is correct. Your first effect grabs some information from the API, then returns a list of Actions that each do something with that data. One might update your state, and another might trigger a subsequent effect that makes the next API call with the data returned from the first one. – David Kidwell Sep 02 '22 at 20:13
  • The syntax has changed a bit in terms of how create/declare effects, but the code inside the effect is pretty much the same I believe. They replaced the @effect decorator with a createEffect(...) function. – David Kidwell Sep 02 '22 at 20:14
  • Here is an example of the new syntax with multiple actions being dispatched from a single effect: https://stackoverflow.com/questions/69099732/ngrx-8-dispatch-multiple-actions-in-single-effect – David Kidwell Sep 02 '22 at 20:15