Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS + Flux - How to implement toasts/notifications?

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?

like image 992
slnowak Avatar asked Apr 15 '15 13:04

slnowak


1 Answers

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.

like image 90
Michelle Tilley Avatar answered Oct 24 '22 11:10

Michelle Tilley