ReactJS + Flux - How to implement toasts/notifications?
Asked Answered
E

2

6

I'm trying to understand Flux and Reactjs.

Consider a following, very simple scenario:

You have a form with few inputs. When user submits form,

ActionCreator.publishAnnouncement(this.state.announcement);

is called inside my form component. This is how the publishAnnouncement method looks like:

var publishAnnouncement = function (announcement) {
  AnnouncementAPI.publishAnnouncement(
    announcement,
    successCallback,
    failureCallback
  )
};

AnnouncementAPI is just a wrapper upon an AJAX http POST call. It takes two callbacks - on success and on failure.

And now: I need to show a notification/toast on the screen - indicating success or failure. How would you do that in a Flux way?

I was thinking about creating Notification component and rendering it inside my form. Like the following:

<Notification title={this.state.notification.title} message={this.state.notification.title} visible={this.state.notification.visibility}  // ?? onTimeExceeded ??     />

But how do I handle those callbacks? Should I create NotificationStore which listens for ANNOUNCEMENT_PUBLISHING_SUCCEEDED and ANNOUNCEMENT_PUBLISHING_FAILED events? In reaction to those events, store emits CHANGE event and thus my Notification updates.

But even if I do that, how should I instruct my Notification to show/hide? Or worse, to show up and hide after 2 seconds?

I've seen few components on GitHub and each of them uses refs etc, which I personally don't like.

To sum up: How would you implement this? Or maybe such project exists? If so, where can I find it?

Eskridge answered 15/4, 2015 at 13:16 Comment(4)
Facebook themselves talk about implementing notifications (user messages) in Facebook using React and Flux in their flux architecture initial video.Alsup
refs are the recommended way of implementing this. Sorry, your personality need to change ;-)Begorra
But shouldn't render be function describing a state of your component in a certain point of time? If so, then using such a component with refs totally breaks it.Eskridge
@BenjaminGruenbaum having Store for user notifications makes sense. Creating one just to fill the popup-component state - probably not?Eskridge
L
6

I don't see anything wrong with having a store solely for notifications, especially if you want logic around showing/hiding notifications on timers, showing multiple notifications, etc.

There are two ways I would consider writing this:

  1. Bind the NotificationStore directly to the success/failure callbacks you care about, like you mentioned in your question. Not sure what flux implementation you're using, so this will be pseudocode-y.

    class NotificationStore {
      constructor() {
        this.notificationId = 0;
        this.notifications = {};
        this.bindActionType(
          CLEAR_NOTIFICATION,
          this.handleClearNotification
        );
        this.bindActionType(
          ANNOUNCEMENT_PUBLISHING_SUCCEEDED,
          this.handleAnnouncementPublishingSucceeded
        );
        // etc...
      }
    
      handleAnnouncementPublishingSucceeded(action) {
        this.addNotification("Success!", { timeout: 2000 });
      }
    
      handleClearNotification(action) {
        this.removeNotification(action.notificationId);
      }
    
      addNotification(message, options) {
        const nextId = this.notificationId++;
        const notification = {
          message: message
        };
    
        this.notifications[nextId] = notification;
        this.emit("change");
    
        // if we specified a timeout, remove the notification
        // after the timeout expires.
        if (options.timeout) {
          setTimeout(() => {
            dispatch(CLEAR_NOTIFICATION, {
              notificationId: nextId
            });
          }, options.timeout);
        }
      }
    
      removeNotification(notificationId) {
        delete this.notifications[nextId];
        this.emit("change");
      }
    }
    
  2. Specify the notifications you want in your action creators. This is more explicit but less centralized.

    var publishAnnouncement = function (announcement) {
      AnnouncementAPI.publishAnnouncement(
        announcement,
        (response) => {
          dispatch(ANNOUNCEMENT_PUBLISHING_SUCCEEDED, ...);
          dispatch(CREATE_NOTIFICATION, {
            message: "Success!",
            timeout: 2000
          });
        },
        (error) => {
          dispatch(ANNOUNCEMENT_PUBLISHING_FAILED, ...);
          dispatch(CREATE_NOTIFICATION, {
            message: "Failure!"
          });
        }
      )
    };
    

    In this case, the NotificationStore would look basically the same, but without binding to each and every success/fail action. In either case, I would have a single Notifications widget near the top of my component tree that rendered the list of notifications.

Letendre answered 15/4, 2015 at 15:40 Comment(1)
From my perspective, the 1st option is much cleaner.Issuance
M
0

In defense of refs (and as the author of the linked GitHub repo): Your stores could emit an event when they change, which would have a handler in the component. This handler would then trigger the notification via the ref. It is much less complex have your component handle the notification through refs instead of props.

Marybellemarybeth answered 9/6, 2015 at 20:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.