NGXS: Is there a way to return a specific value after an action is completed

Viewed 1245

Let's say we have an action in state that handles the creation of a new list:

@Action(CreateList)
    async createList(
        ctx: StateContext<StateModel>,
        { payload }: CreateList
    ) {
        // Create a new list
        const newList = await this._listServiceProxy
            .create(payload.listId, payload.input)
            .toPromise();

        ctx.setState(
            patch<StateModel>({
                 lists: append([newList])
            })
        );
    }

And let's say we need the new ID of the created list.

Currently, the action dispatch only returns an observable that receives the new state after action completion. Fetching the last list in this scenario works, but it's not always easy to find a workaround depending on the usage.

How can I send back the created list id?

1 Answers

According to the answers I got on NGXS's official slack channel, returning a value from an action dispatch is an anti-pattern. Thus the following solution was offered (thanks @poloagustin!):

  1. Store the list Ids in the state as well.
  2. Push the newly created list's Id to it after adding it to the lists array on creation.
  3. Use actions's life cycle to detect the end of the action dispatch.
  4. Use selectors to get the ids' array.

The Action:

@Action(CreateList)
    createList(
        ctx: StateContext<StateModel>,
        { payload }: CreateList
    ) {
        // Creation logic

        return ctx.setState(
            patch<StateModel>({
                 lists: append([newList]),
                 newIds: patch({[payload.listId]: newList.map(({id}) => id)}) 
            })
        );
}

And in the component:

const postCreateListOperationsSubscription = this.actions.pipe(ofActionSuccessful(CreateList), tap(({payload}) => {
  const newIds = this.store.select(state => state.app.newIds[payload.listId]);
}))
Related