Tips for sending multiple commands in ngrx/effect (redux-observable)?

In my Angular 6 project, I am using ngrx/store to manage state. I have an effect that handles updating data and based on certain conditions, I need to dispatch different actions. What will be the impact of using switchMap instead of map in this scenario?

Here is the code snippet that I attempted but encountered some issues:

 @Effect()
  dispathMultipleActions$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    map(() => {
      const actions: Action[] = [];
      const array = [1, 2, 3, 4, 5];
      array.forEach(item => {
        if (item > 3) {
          actions.push(new DeleteAction(item));
        } else {
          actions.push(new ChangeAction(item));
        }
      });
      return actions;
    })
  );

Answer №1

An effect changes a series of actions, taking in a stream of actions and producing an output stream of actions. In the provided example, each action is mapped to an array of actions. However, a stream of arrays of actions is not a valid output. To correct this, the array must be flattened so that each individual element is emitted into the output stream instead of the array as a whole.

Instead of:

input:  --a-------a------>
output: --[b,c]---[b,c]-->

You should aim for:

input:  --a-------a------>
output: --b-c-----b-c-->

To flatten an Observable containing arrays into Observables of each individual element, operators like mergeMap, switchMap, or exhaustMap can be used. In most scenarios, mergeMap is the suitable choice. For further information on these operators, refer to this answer.

@Effect()
register$: Observable<Action> = this.actions$.pipe(
  ofType(AuthActionTypes.REGISTER_REQUEST),
  mergeMap((action: RegisterRequest) => {
    // check for successful register request
    return [
      new RegisterSuccess(),
      new LoginRequest(action.payload)
    ]
  })
);

Answer №2

In a similar scenario (assuming the usage of NgRx 10 or newer), I have a unique viewpoint on how to approach effects. Firing off multiple actions sequentially in one location, especially within a single effect, is considered an anti-pattern. It is crucial to maintain a coherent overall flow of application state in NgRx based on actions and potential state modifications, as envisioned by the NgRx architecture.

Adhering to the 3 rules for effects can help prevent complex scenarios:

  1. Name effects according to their purpose
  2. Ensure each effect has a single responsibility
  3. Only emit a single action per effect

Following these guidelines not only promotes the separation of concerns design pattern but also enhances the testability of NgRx effects.

In your specific case, you can separate the desired additional actions by using an intermediary proxy action.

It appears that the original effect dispathMultipleActions$ may not be necessary in your scenario, unless it contains specific logic that could be better suited in a state Reducer, further improving testability.

If ActionTypes.UpdateSomething already includes an array payload object, you could break down your dispathMultipleActions$ into individual actions, like so:

@Effect()
deleteAction$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    concatMap(from(new Promise((array) => {
        array.forEach(item => {
            if (item > 3) {
                // perform desired action
            }
        });
    }))),
    {dispatch: false}
);

@Effect()
changeAction$ = this.actions$.pipe(
    ofType(ActionTypes.UpdateSomething),
    concatMap(from(new Promise((array) => {
        array.forEach(item => {
            if (item <= 3) {
                // perform desired action
            }
        });
    }))),
    {dispatch: false}
);

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

What is the best way to implement an ng-change function on multiple fields within the same page without causing a cyclic call loop?

In my page, I have three angular-moment-datepicker fields - a date picker field, a month picker field, and a year picker field respectively. Here is the code: <input class="form-control" placeholder="BY DAY" ng-model="date" moment-picker="gDate" start- ...

Redux Form: Input remains untouched with `touched: false'

Looking to validate my input fields and dynamically change the CSS based on user interaction. To start, I implemented a required validation method by wrapping all input components with a <Field> tag and passing an array of functions to the validate ...

When using selenium with python, the function excecute_script('return variable') may not technically return variables, even though the variable does exist

My attempt to retrieve a variable from javascript code using selenium is encountering difficulties. Despite the presence of the variable (confirmed by inspecting the source code before executing the script), the command driver.execute_script('return v ...

What method can be used to specify a function of any signature that returns a particular type in programming?

I am looking to define a unique type that must be a function which, when executed, will always produce an object containing the property type: string. The input parameters for this function are of no concern. For instance: foo(1, 'bar'); // res ...

Is there a way to transform this pledge back into a JSON array format?

My goal with this code is to retrieve a JSON array from my server. var students_list; const library_address = 'http://localhost:17330' async function fetchData(param1, param2) { if(param1 == 'getdata') { const response ...

Unable to Call ZF2 Controller Function

I have been attempting to send a post value to the OrderController using ZF2. I have included JavaScript code in the view folder. Below are the codes: function submitHandler(form) { var urls = '<?php echo $this->baseurl; ?>/order/save ...

Webpack generates unique hashed file names for images within the project

Within one of the components located in my client/components directory, I have imported three images from the public/images folder. Recently, webpack generated hashed files for each image such as: 0e8f1e62f0fe5b5e6d78b2d9f4116311.png. Even after deleting t ...

efficiently managing errors in a Nest Jest microservice with RabbitMQ

https://i.sstatic.net/sUGm1.png There seems to be an issue with this microservice, If I throw an exception in the users Service, it should be returned back to the gateway and then to the client However, this is not happening! The client only sees the de ...

The download progress of a substantial blob from the API to the user is not displayed until the entire download is complete

Recently, I encountered a problem similar to one described in this post. However, the original post lacked details and context, so here's what I've found: When my component triggers the download file method, which then calls the download file se ...

I'm having trouble inputting text into my applications using React.js and TypeScript

I am encountering an issue where I am unable to enter text in the input fields even though my code seems correct. Can anyone help me figure out what might be causing this problem? Below is the code snippet that I am referring to: const Login: SFC<LoginP ...

Trigger the rowContextMenu in Tabulator Table by clicking a Button

Is there a way to add a button at the end of a table that, when clicked, opens a rowContextMenu below the button? Additionally, can the rowContextMenu pop up when right-clicking anywhere on the row? I have attempted some solutions without success. Here is ...

I'm experiencing some issues with the JavaScript setTimeout function - can anyone help troubleshoot

in my quest to find a way to hide the notificationBar without the use of a button and using XX.hide() oncomplete, I stumbled upon a javascript snippet <script type="text/javascript> jQuery(function() { bar.show(); setT ...

Leveraging Angular for Remote Configuration Management

How is everything going with you? I'm attempting to retrieve a configuration that I previously set up in Firebase's remote config using my Angular 15 application. The specific configuration is called "AllowedUsers." Here is the image of th ...

ES6 promises: the art of connecting functions with parameters

Looking for a way to chain functions with delays? Here is an example of what I have tried: Promise.resolve() .then(setKeyframe('keyframe-0')) .then(delay(3000)) .then(setKeyframe('keyframe-1')) .then(delay(3000)) .then(setKeyframe(&apo ...

Dynamic Node.js server constantly updating

My goal is to create a dynamic Node.js Express server that updates live, possibly by creating a specific route like /update to load a new configuration file. My concern is that the server could be in any state when the update occurs. It's possible tha ...

Incorporating jQuery to seamlessly add elements without causing any disruptions to the layout

I'm looking to enhance the design of my website by adding a mouseenter function to display two lines when hovering over an item. However, I've encountered an issue where the appearance and disappearance of these lines cause the list items to move ...

What is Mozilla's reasoning for deeming Conditional catch-blocks as non-conventional?

I recently came across a document on Mozilla that described the try...catch conditional as "non-standard and is not on a standards track. Do not use it in production" However, I am curious to understand the reason behind this statement. I also want t ...

Replace the value of a variable when another variable becomes false in Angular.js

Currently, I am working on a project using Angular and have run into an issue that I need help with: In my project, I have two variables - signed which is a boolean bound to a checkbox, and grade which is an integer bound to a number input field. I am lo ...

Development with Node JS, express, Mongoose, and intricate nested queries

I'm struggling with a group of interconnected queries using express/mongoose, structured like this: app.get(..., function(...) { Schema1.query(..., function(..., res1) { for ( var key in res1 ) { Schema2.query(..., function(..., ...

Removing data from every page of a table with the Datatable plugin

Currently, I am facing an issue with a table of data that I am handling using the Datatable plugin. My goal is to clear the table upon clicking a button and then redraw it with updated values received via an ajax call. The problem arises when trying to del ...