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

What is the best way to trigger actions from child components within React Redux?

My server contains the following code snippet: <ReactRedux.Provider store={store}><Layout defaultStore={JSON.stringify(store.getState())}/></ReactRedux.Provider> The <Layout> component includes more nested components. Further dow ...

Using angularjs to include content from other files is known as

As I delve into the concept of creating directives in AngularJS, I am faced with the imminent end of Angular 1.x and the rise of Angular 2.x. The shift seems daunting, but I am determined to bridge this gap seamlessly. In my quest for clarity, I stumbled ...

When using angularjs, the $window.location.href may cause the page to load without any

I have a dilemma where I have linked all my CSS and JS files in the index.html file, but subpages are located in a templates directory. When using $window.location.href, only a plain HTML page is returned without any CSS styles. The page renders fine when ...

What is the best way to initialize a value asynchronously for React context API in the latest version of NextJS, version

Currently, I'm working on implementing the React context API in my NextJS e-commerce application to manage a user's shopping cart. The challenge I'm facing is how to retrieve the cart contents from MongoDB to initiate the cart context. This ...

Managing OAuth2 redirections on the frontend: Best practices

I am currently working on implementing an OAuth2 flow for a Single Page Webapp, but I am facing challenges in dealing with Frontend/JavaScript redirects. Regarding the backend setup, I have it all sorted out: utilizing a library that takes care of everyth ...

Tips on specifying a default value when receiving data from an API

I am working with a dropdown list that is populated from an API call. Here is my code snippet: <label>User Code:</label> <select ng-options="c as c.User for c in userList" ng-model="selectedUser" id="search3"> </select> To fet ...

What could be the reason behind the malfunctioning of a custom filter in this specific Vue 3 application?

In my development project, I am creating a Vue 3 CRUD application for managing Users. The goal is to display the users in reverse order so that the newest additions appear at the top. To achieve this, I have implemented a custom filter as shown below: reve ...

Conditional Matching with Javascript Regular Expressions

My strings are formatted like this: #WTK-56491650H #=> want to capture '56491650H' #M123456 #=> want to capture 'M123456' I am trying to extract everything after the # character, unless there is a dash. In that case, I onl ...

create a JavaScript array variable for posting items

My goal is to use this javascript to make four posts for the 'var msg' array. However, it currently posts 'encodeURIComponent(msg[i])' four times instead. How can I resolve this issue? var msg = ['one', 'two& ...

extract the key identifier from the JSON reply

My JSON ResponseData example for form0 is provided below: { "MaterialType": "camera", "AssetID": 202773, "forms": [ { "release": "asyncCmd/accessCameraMulti", "action": "rest/Asset/202773/cameraAccessMultiple", ...

Ordering and displaying data with AngularJS

Trying to maintain a constant gap of 5 between pagination elements, regardless of the total length. For instance, with $scope.itemsPerPage = 5 and total object length of 20, we should have 4 pages in pagination. However, if $scope.itemsPerPage = 2 and tota ...

Making an Ajax request to trigger a method within a controller

Here is the code snippet I wrote: $(function () { $("input#Submit1").on('click', function () { $.ajax({ url: 'Home/GetPort', method: 'GET' }); alert("test") ...

If the FedEx function does not receive a payment, it will need to return a value of Payment Required

I am struggling with understanding functions, parameters, and arguments in JavaScript as I am new to it. My goal is to have a function that returns different values based on the payment amount. If no payment is passed, it should return "Payment Required", ...

Is there a way to automatically redirect the server URL when a file is modified?

I am currently experimenting with a function that is supposed to only display a message in the console without redirecting the actual URL of my server when a file is changed. watcher.add("/home/diegonode/Desktop/ExpressCart-master/routes/2.mk"); watche ...

Javascript tabs with clickable links

I have created a page with a series of thumbnails that reveal content below when clicked. The content is positioned absolutely and set to display:none, with javascript changing this for each thumbnail. (I am not very familiar with javascript and learned t ...

Error Message: SCRIPT5 - Permission Denied When Trying to Open PDF with Javascript

Despite searching through multiple posts on SO, I have yet to find a solution to my issue. We operate a web form within our LAN that utilizes Javascript's OPEN function to open PDF files. Up until recently, everything was working smoothly. However, ...

Utilize moment.js to format a datetime and display the corresponding timezone

I'm having trouble displaying timezones correctly using moment.js. I attempted to use the following code: var result = moment(someDate).format("MM/DD/YYYY HH:mm A Z"); This returns something like: 08/05/2015 06:18 PM +02:00, which is okay, but I w ...

Guide on getting a website name from a URL using Javascript

Is there a simple method to extract the site name from a URL string? For example: http://www.mysite.com/mypath/mypage -> www.mysite.com http://mysite.com/mypath/mypage -> mysite.com The JavaScript code runs on the mongodb CLI side, not within ...

Transformation of firebug console information into a function()

Snippet of JavaScript code: KT_initKeyHandler(b) Firebug console output: KT_initKeyHandler(b=keydown charCode=0, keyCode=90) Corresponding JavaScript function call: KT_initKeyHandler(?) Example: Snippet of JavaScript code: KT_event(b,c) Firebug ...

Tips for passing props while clicking on a v-data-table:

I am currently facing an issue in my app while using v-data-table. I am able to pass props with an extra slot, but I want the entire row to be clickable in order to open a dialog with the prop item: <template v-slot:item.actions="{ item }"> ...