How to effectively dispatch actions using @ngrx/store: Exploring the benefits and best practices

Currently, I am immersed in a project that involves Angular 2 and @ngrx/store. I have a question regarding best practices and how to effectively execute certain actions.

In my development process, I have created a "web finder" tool for file management. This tool enables basic functionalities such as copying, moving files, etc.

Let me outline the steps involved in moving a file:

  • Logic: Perform necessary verifications.
  • Dispatch action A
  • Dispatch action B

Initially, I had these 3 steps executed within my Angular component. However, upon reflection, I believe it would be more efficient to consolidate them into one action - performing verifications and then dispatching subsequent actions.

Why opt for this approach? Firstly, it significantly improves readability:

this._store.dispatch(copy(myFile));

as opposed to

// ...
// verifications
// ...

this._store.dispatch(action1(myFile, foo, bar));
this._store.dispatch(action2(myFile));

Furthermore, dispatching the 'copy' action on-the-fly eliminates any potential side-effects since verifications are handled within the action itself.

In essence, by centralizing logic within actions, components can remain simple and focus on their primary tasks (UI management).

Question 1: Is this considered good practice?

While I personally find this approach beneficial, I'm keen to hear about your experiences and insights.

Question 2: How should I proceed?

Implementing this methodology poses a challenge when dealing with action creators solely as functions without the ability to utilize decorators like 'Injectable' or inject instances using 'constructor.'

Here's an example of action creators:
import { Action } from '@ngrx/store'

export const NAVIGATE_TO_NODE:string = '[Browser] Navigate to node';
<!-- Additional action constants omitted for brevity -->
  
export const navigateToNode:(nodeId: number, paneId?: number)=>Action = (nodeId: number, paneId?: number) => {
  return {
    payload: { nodeId, paneId },
    type: NAVIGATE_TO_NODE
  };
};
<!-- Additional action creators omitted for brevity -->

To address this issue, having prior experience with Redux in React projects, I discovered a useful library called redux-thunk which facilitates dispatching actions directly from action creators.

Answer №1

I agree with wiredprogrammer's recommendation to check out the ngrx example app, which demonstrates how to organize actions, reducers, and effects.

Take a look at this sample injectable action class:

@Injectable()
export class BookActions {
  static SEARCH = '[Book] Search';
  search(query: string): Action {
    return {
      type: BookActions.SEARCH,
      payload: query
    };
  }

Then in your component...

constructor(private store: Store<AppState>, private bookActions: BookActions) {}

search(query: SearchOutput) {
  this.store.dispatch(this.bookActions.search(query));
}

Here's an approach to consider: Reducers should be pure functions without side effects. For instance, when moving a file, you can dispatch an action to start the transaction, setting the state with necessary details like file name and destination. The reducer function could be named START_MOVE.

In your effects, listen for START_MOVE, retrieve the transaction details from the state, and perform the initial part of the transaction. Upon completion, dispatch an action with the updated state to MOVE_2 or a more descriptive name.

This reducer updates the state with information needed for the next step before returning it.

The effects monitor MOVE_2, execute the second stage of the transaction, and then dispatch MOVE_3. This process continues until the final step is reached, where MOVE_SUCCESS sets up the state with the finalized changes.

If an error occurs at any point, dispatching MOVE_ERROR allows for cleanup or a return to the initial state. Likewise, MOVE_CANCEL can be used if desired.

A component can observe the state and provide status updates to the user.

Answer №2

Apologies for the brevity, as I have only quickly glanced over your inquiry and am responding to just a portion of it. To make your action creators injectable, consider wrapping them in a class structure. For inspiration on how to structure this, refer to the ngrx example app linked in the readme for ngrx/store. I've implemented a similar setup for action creators in a project that I'm currently working on.

https://github.com/ngrx/example-app/tree/master/src/actions

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

A guide to successfully transferring textarea content to the clipboard in an Angular application

I'm struggling with a task in an Angular 7 application where I have a textarea and need to copy its content to the clipboard when a button is clicked. I've implemented the following code in the button's click handler: if (this.txtConfigFile ...

Angular 4 with Universal: Implementing 404 Status Code in Header for /404 Page Component

After researching and reviewing numerous StackOverflow inquiries, I have come to the conclusion that headers are derived from responses served by servers, making it a non-issue. I attempted to rectify the situation from my server.ts file but unfortunately ...

Steps for mocking an async action creator in Redux using Jest

I am currently working on writing a unit test for a redux async action creator using jest. asyncActions.js: const startSignInRequest = () => ({ type: START_SIGNIN_REQUEST }); // this is the action creator for successfully signing in a user export c ...

Struggling to run Jest tests on ajax modules that utilize axios

I am facing an issue while testing a function called status from the module ajax.js using Jest. export const status = ({loginUrl='/', logoutUrl='/'}) => { return axios.get(`/auth?login=${loginUrl}&logout=${logoutUrl}`); }; In ...

Error encountered in Typescript React: JSON API Object expecting a ":" when indexing

Using Axios in Typescript React to fetch API Data. Here is a glimpse of the JSON Data :https://i.sstatic.net/DCXTz.png Trying to access the number value at index 1.tokenAmount.uiAmount Currently attempting data?[1]["tokenAmount"]["uiAmount"], but encoun ...

What methods can be utilized to extend the duration of ngxtoastr's display time?

Is there a way to extend the display duration of ngx-toastr notifications when using toastr.success for success messages fetched from an API? this.toastr.success(this.successMessage); ...

Tips and techniques for performing Ahead-Of-Time (AOT) compilation using Angular-CLI in your

Currently working on an Angular4 project and exploring the necessity of using AOT with Angular-CLI. Since Angular-CLI operates Webpack2 in the backend and webpack can generate production builds using ng build, is it required to also use AOT with CLI? Furt ...

Oops! There seems to be an issue. The system cannot locate a supporting object with the type 'object'. NgFor can only bind to Iterables

onGetForm() { this.serverData.getData('questionnaire/Student Course Review') .subscribe( (response: Response) => { this.questionnaire = response.json(); let key = Object.keys(this.questionnaire); for ...

Challenge encountered with asynchronous angular queries

Dealing with asynchronous calls in Angular can be tricky. One common issue is getting an array as undefined due to the asynchronous nature of the calls. How can this be solved? private fetchData(id){ var array = []; this.httpClient.get('someUrl ...

Steps to enable the submit button in angular

Here's the code snippet: SampleComponent.html <nz-radio-group formControlName="radiostatus" [(ngModel)]="radioValue" (ngModelChange)="onChangeStatus($event)"> <label nz-radio nzValue="passed">Passed</label> <label nz-rad ...

Simplify deeply nested JSON structures with TypeScript generics

After receiving the JSON data shown below, I have a specific model in mind for deserialization: {"results": {"data": { "id":"93cba9bd-2969-3214-b26f-7f42d20241a4", "first_name":"PSU", "last_name":"Bot", "profile": { "data":{"abou ...

Can ngx permissions in angular be trusted for ACL management?

Currently working with Angular 6 and looking to manage user access control. While the conventional wisdom is to handle ACL in the backend, there are packages like ngx permissions available for managing it on the frontend. Is it secure to utilize these fe ...

`Angular2 - exploring the complexities of function scope`

I'm facing a challenge while working on my Angular2 Sample with the http module. Here is a snippet from my component: app.loginComponent = ng.core.Component({ selector: 'login', templateUrl: 'app/login/login.html&ap ...

Adding information after verifying it against JSON data

I'm feeling a bit lost right now. Despite investing a considerable amount of time into it, I haven't been able to find a satisfactory solution to my issue. Therefore, without further ado, let me explain my question. My JSON data consists of an a ...

Having trouble deploying Firebase Cloud function following the migration to Typescript

After following the steps outlined in the firebase documentation to convert my cloud functions project to TypeScript (see https://firebase.google.com/docs/functions/typescript), I encountered an error when attempting to deploy using 'firebase deploy - ...

Is it possible to schedule deployments using Vercel Deploy Hooks in Next.js?

When we schedule a pipeline on git, I want to schedule deploy hooks on vercel as well. Since the app is sending getStaticProps and every HTTP request will be run on every build, I have to rebuild the site to get new results from the server. For instance, ...

Combining and forming a distinctive case-sensitive array in JavaScript

Explaining a complex scenario, I have one object or array and one array. My goal is to compare selectedmodel values with mappedmodels. If the value (case insensitive) matches any key in the object, I need to fetch all associated values and push them into t ...

Is there a way to transmit a live audio recording in Ionic to Firebase?

I'm looking for a way to achieve live speech-to-text recognition using Google API service in an Ionic frontend. I've been searching for a library that can capture audio in real-time on Ionic and stream it directly to Google Cloud's storage b ...

What is the correct way to express an object in an array?

I've encountered an issue: I'm working with an array called _daysConfig<DayConfig> When I manually populate it like this, everything functions correctly: _daysConfig: DayConfig[] = [ { date: new Date('Wed Jul 22 2020 21:06:00 GMT+02 ...

Angular: Refresh Mat-Table data following any changes

I'm currently working with a Mat-table that has expandable rows, each containing an update functionality for the data. While the POST and GET requests are functioning properly, I encounter an issue where I need to reload the page in order to see the u ...