An elaborate warning mechanism in Redux-observable that does not trigger an action at the conclusion of an epic

I'm currently working on implementing a sophisticated alert system using redux and redux-observable.

The requirements are:

  • An action should request an alert: REQUEST_ALERT
  • An action should create an alert and add an ID: SET_ALERT (handled in the epic)
  • An alert should automatically close after 3 seconds: DISMISS_ALERT (handled in the epic)
  • An alert can be manually closed by a user click: DISMISS_ALERT

(We could potentially refactor to directly use SET_ALERT without REQUEST_ALERT inside the reducer, but that's not the main issue at hand here).

I've made significant progress with the following code snippet:

// Generate the alert from the request
// This section may be ignored if refactored to only use REQUEST_ALERT
export const generateAlert$ = (action$) => {
  return action$.ofType(REQUEST_ALERT)
    .map(action => ({
        type: SET_ALERT,
        payload: generateAlertPayload(), 
        // Simply creating an action of type SET_ALERT and adding an ID 
      })
    )
}

// The crucial part of the implementation
export const timeoutDismissAlert$ = (action$) => {
  return action$.ofType(SET_ALERT)
    .mergeMap(action =>
      Rx.Observable.empty()
      .concat(
        // Wait for the maximum delay before sending the dismiss_alert payload
        Rx.Observable.of(action)
          .delay(maxDelay)
          .map(({payload}) => ({type: DISMISS_ALERT, payload: payload.id}))
          // Create a race between the user click and the delay 
          .race(
            action$.ofType(DISMISS_ALERT)
              .skipWhile(({payload}) => payload !== action.payload.id)
              .first()
              .map(() => null)
          )
      )
      // Dispatch an action only if the delay wins
      .map((a) => a ? a : {type: "I_DONT_WANT"})
    )
}

Is there a way to avoid dispatching an action at the end of an epic? Or is there a more efficient RxJS approach to achieve this?

Answer №1

It seems like you're wanting to stop a delayed observable whenever a user clicks, and using takeUntil can help achieve that.

The epic you may be looking for could resemble the following:

// defining an action creator
const dismissAlert = payload => ({ type: DISMISS_ALERT, payload });

// creating the epic
const dismissAlert$ = action$ => {
    return action$.ofType(SET_ALERT)
        .mergeMap(action => {
            const dismiss$ = action$.ofType(DISMISS_ALERT)
                .filter(({ payload }) => payload === action.payload.id);

            // the crucial part
            return Rx.Observable.timer(maxDelay)
                .mapTo(dismissAlert(action.payload.id))
                .takeUntil(dismiss$);
        });
};

By nesting the observables this way, it will emit either a single DISMISS_ALERT action or nothing if the user clicks before the maxDelay interval is over.

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

Scrolling through a list of objects in a React component to display a vertical lineup of items including the name and logo

Currently, I am working on developing a vertical scrolling ticker/item list that showcases both the name and logo of each item within an array. Initially, I had set up a scrolling ticker solely with names using webkit animations on styled components. Howev ...

Using a Node.js module to shrink HTML files

Is there a way to minify HTML before rendering it? I'm aware of console minifiers like: html-minifier However, I am looking for a solution that can be implemented in the code itself. Something along the lines of: var minifier = require('some- ...

JavaScript Challenge: Calculate the Number of Visible Characters in a Div

I have a div with text content (a string of length S) that is fixed in size but can be of any length. When the text exceeds a certain point (referred to as L), it gets truncated, and the portion beyond that limit becomes invisible. In other words, characte ...

"Effortlessly move elements with HTML5 drag and drop functionality from either direction

I'm working on an application that requires Html5 Drag and Drop functionality, which is currently functioning well. However, in the app, there may be instances where a dropped item is no longer needed and I want to allow users to re-drag and drop it b ...

Bootstrap dropdown menu with Javascript List group

<div class="btn-group"> <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria- expanded="false"> Sort <s ...

Updating the ID's of nested elements in JavaScript when duplicating an element

After a fruitless search on Google, I have turned to the experts on SO for assistance. The challenge: Create a duplicate of a dropdown menu and an input field with the click of a button (which can be done multiple times) The proposed solution: Implement ...

What could be causing my resize event to not trigger?

My goal is for the #sequence div to be full height of the browser window when the window size is greater than 920px in height. In such cases, I also want to trigger a plugin. If the window size is lower than 920px, then the height of the #sequence div shou ...

Transferring information between two separate components

Hey there, I'm struggling with the Payment Component. What I want to achieve is that when I click on a link, it transfers (ClassG, imageG, and PriceG) to the Payment Component where I can then style them accordingly. I've attempted something, but ...

Inconsistency in the invocation of PageMethod within AJAX script manager

My AJAX call to a method in the code-behind seems to be unreliable even though I have everything set up correctly. The JavaScript function utilizes PageMethods to invoke the method in the code-behind. While most of the time it works fine, occasionally it ...

Stop the print dialog box from appearing when using the Ctrl + P shortcut

I'm working on an Angular app and I want to prevent the print dialog from opening when pressing "Ctrl + P". To address this issue, I have implemented the following code: window.onbeforeprint = (event) => { event.stopPropagation(); cons ...

Ways to stop the location object from resetting in ReactJS when reloading the page

Currently, I am using Link to redirect and call another component. The code looks something like this: <Link to={{ pathname: "/app/" + app.appId, appDetail: { app: app } }}>> When I call the path /app/:appId, it triggers the AppDetails ...

Mastering sorting in AngularJS: ascending or descending, the choice is yours!

I have set up a table view with infinite scroll functionality. The table contains 2000 objects, but only shows 25 at a time. As the user scrolls to the bottom, it loads an additional 25 elements and so on. There is a "V" or "^" button in the header that sh ...

What is the best way to assign multiple event handlers to Solid.js components within a single HTML element?

Introduction I am currently exploring Solid.js and facing a challenge in adding multiple event handlers to the same HTML element from different components using JSX. While it's straightforward in Vue, I have noticed that Solid.js overrides events bas ...

Exploring the Open method in AJAX and its impact on synchronicity

I am in the process of creating a webpage that utilizes the openweathermap.org API. However, I am encountering an issue when making an AJAX call and trying to access the API using weather.open(blah, blah, true). function executeWeatherCity(cityName){ ...

Persistent error function arises from Ajax request in Laravel

Greetings everyone. I'm currently working on my Laravel application and trying to verify the attendance for a specific date, subject, grade in my database table. If the data exists, I have implemented an if statement to display the desired results bas ...

Making modifications to the state within a modal dialogue box

I am developing a note-taking application where users can write a title and note, and when they click submit, the note is displayed on the page. I want to implement an editing feature where clicking on the edit button opens a modal with the user's tit ...

Unlimited scrolling with jQuery/Ajax

I am currently working on implementing infinite scroll functionality using ajax, php, and mysql in my web application. However, I am facing difficulty in loading new content only when the user reaches the end of the page. Currently, all the data is loaded ...

The screen is cloaked in a dark veil, rendering it completely inaccessible with no clickable

Utilizing Bootstraps modals, here is my current layout. Within the site's header, there exists a "settings" button that triggers a modal containing various options. These options are not tied to the question at hand. The button responsible for displ ...

The elegant-admin template's mobile navigation toggle is missing

I recently downloaded an admin theme and added the CSS to my Django static files. However, after doing so, the mobile toggle feature disappeared. I double-checked all the CSS and JS links in the index template, and they are correctly linked to the paths, b ...

Latest output is fetched by jQuery from the load() method

I'm encountering an issue with the code present in index.html: $(document).ready(function() { $('#generate').click(function() { //$("#results").empty(); $("#results").html(""); $("#results").load("generate.php"); }); }); In addition ...