Akita: Custom action not displayed in Redux DevTools

Created on 27 Jul 2018  路  11Comments  路  Source: datorama/akita

I'm submitting a...


[ ] Regression (a behavior that used to work and stopped working in a new release)
[x] Bug report 
[ ] Performance issue
[ ] Feature request
[ ] Documentation issue or request
[ ] Support request
[ ] Other... Please describe:

Current behavior

Skills - @Transaction gets displayed instead of the defined custom action in Redux DevTools. Neither @action nor applyActiondoes work.

Expected behavior

Redux DevTools should display [Skills Service] Fetch All.

Minimal reproduction

https://stackblitz.com/edit/akita-todos-app-uiqjdx?file=src%2Fapp%2Fskills%2Fskills-data.service.ts

Am I doing it wrong by defining the custom action in the main service? It's the only place it makes sense for me. Thanks for your support!

bug

Most helpful comment

:tada: This issue has been resolved in version 1.3.2 :tada:

The release is available on npm package (@latest dist-tag)

Your semantic-release bot :package::rocket:

All 11 comments

:tada: This issue has been resolved in version 1.3.2 :tada:

The release is available on npm package (@latest dist-tag)

Your semantic-release bot :package::rocket:

@NetanelBasal, that was fast, thank you! It seems to have partly fixed the issue. I updated the Stackblitz above to illustrate the remaining part more clearly. Here's a summary of my observations:

  @action({ type: '[Skills Service] Fetch All' })
  fetchAll() {
    this.skillsDataService.getAll().pipe(
      tap(entities => {
        applyAction(() => {
          this.skillsStore.set(entities);
        }, { type: '[Skills API] Fetch All Success' });
      }),
      catchError(error => {
        return applyAction(() => {
          console.warn(error);
          return error;
        }, { type: '[Skills API] Fetch All Error' });
      })
    ).subscribe();
  }
  1. When running the application the Skills state is not initialized (or at least there is no entry in DevTools).
  2. When clicking on "Fetch skills", I would expect from the above code to dispatch [Skills Service] Fetch All before making the fake API call and then either Success or Error when receving the response. In DevTools I only seem to get the Success or Error part, @action still seems to get ignored.
  3. When the Success action runs for the first time, the Diff is empty in DevTools, although the state is populated with the correct data. This might be connected to the previous point.
  4. Minor thing but is there a reason for not capitalizing @action for consistency with other decorators?

PS. It seems to be a commonly troublesome to link non-redux state management frameworks with the Redux DevTools. NGXS has a similar issue being unable to display Dispatch -> Success || Error in the right order (explanation in the linked comment). It seems that they could be solving this via some lifecycle hooks within the @Action decorator.

  1. It's because the store is initialized in the app component before you calling the dev tools. If you move it to a component, you will see the expected result. (I will try to understand how to support the app component as well)
  2. The problem is that in Akita, actions are dispatched only upon update. I can add this feature, what do you think about:
    @action({ type: '[Products Service] Fetch All', force: true })
  3. Yes, it's related.
  4. Class decorators have capitalized wheres methods decorators aren't.

Successfully fixed everything according to my previous comment. I'd love to hear your thoughts first.

After discussing with the team, we decide that it's not correct to add the force attribute. Action should be dispatched only upon store update. In Redux, for example, when you call [Fetch All], you are usually updating the loading key and change it to true so you can show a spinner.

@NetanelBasal I could successfully solve 1 and 3 by moving everything out of AppComponent.

As for the 2nd, I tend to agree with you and your team. I already modified the Stackblitz and tried this out:

@action({ type: '[Skills Service] Fetch All' }) fetchAll() { this.skillsStore.setLoading(); <----------------------------- this.skillsDataService.getAll().pipe( tap(entities => { applyAction(() => { this.skillsStore.set(entities); }, { type: '[Skills API] Fetch All Success' }); }), catchError(error => { applyAction(() => { this.skillsStore.setLoading(false); <----------------------------- this.skillsStore.setError(error); <---------------------------- }, { type: '[Skills API] Fetch All Error' }); return error; }) ).subscribe(); }

Now it fires all 3 actions accordingly, so Akita's actions are pretty intelligent already to figure such a case out. Props!

There's only one issue left. The Fetch All action altough fired, it seems to show the wrong Diff (loading from true to false). Feel free to check out the Stackblitz. Thanks for the amazing work and blazing fast answers!

There is no need to call setLoading(). Akita already initializes the store with loading set to true. When you call set() it will automatically set it to false.

You can use the query.selectLoading() method to toggle a spinner in your view. Check out the docs for more information.

If you have any further questions, let me know.

This triggers two questions in my head:

  1. Is it fair to initialize the entity store with loading set to true without even calling the API request (as in Fetch All)? It somehow feels like magic that perhaps cannot cover 100% of the use cases.
  2. If this behavior won't change, how do I get the Fetch All to get dispatched? I have nothing to update in the store, since loading has already been magically set to true.

If you think about it, in 99% of the cases you will call the API when the component is initialized, so basically, we are saving you the setLoading call.

You can always start the loading with false.

export class TodosStore extends EntityStore<State, Todo> {
  constructor() {
    super( { loading: false} );
  }
}

Setting { loading: false } in the initialState of the store does the trick! Then it's just a matter of this.skillsStore.setLoading(true); in the Fetch All action to get it dispatched with the right Diff.

It might be helpful for newcomers to include the lessons learned from this thread into the docs. I would see the following:

  1. After the last sentence on Loading State:

You can also initialize the entity store with the loading state set to false:
[paste your code from above]

  1. Under the Custom action paragraph:
    The custom actions will only be dispatched on update of the state.

And perhaps give an example with the Dispatch - Success || Error pattern.

Akita :heart:

Done. Thanks. If you have any further question or feedback, let us know.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

NetanelBasal picture NetanelBasal  路  6Comments

stherrienaspnet picture stherrienaspnet  路  3Comments

mikejr83 picture mikejr83  路  6Comments

eitanfr picture eitanfr  路  4Comments

brgrz picture brgrz  路  4Comments