Notifications with React and Redux

Update 14/03/2017 – better implementation

After recently completing the excellent Reddit API tutorial from the official Redux documentation, I got to implementing a very similar set up in my own application.

One thing pointed out – but not really covered in the tutorial – is that sometimes (more often than I would like to believe, no doubt), communication between the front end and the back end will break.

Now, this sucks for many reasons. But from a user’s perspective, my reasoning is they won’t be as bothered if a little notification / pop up helpfully pops up and says: “heads up, that didn’t work… try again!”

Ok, so they try again and it doesn’t work again. Bad times. Maybe I need to work on my helpful error messages. Or better yet, fix the damn system.

But, message content and flaky systems aside, I decided I wanted to keep track of my notifications via Redux / the application state.

I figured this would be a solved problem. And it is. Kind of.

I found quite a few libraries that already solve this problem, in one way or another:

  • React Toolbox – Snackbar component
  • Igor Prado’s React Notification System
  • Patrick Burtchaell’s React Notifications

And there were others.

I also found a lot of not-React-ified code:

  • Toastr
  • Growler
  • Alertify JS

There’s probably a ton more. It seems like a common problem, with a variety of solutions.

But none of them were Redux-ready, right out of the box. At least, not that I could see.

Being new to Redux, I found this a little worrying (ack, how to do this myself?!) but also an interesting challenge (ack, with what I know so far, can I even do this myself?)

It’s worth noting that the React Toolbox Snackbar component does everything I need. Only, it has a material design theme to it, which I didn’t want. I also didn’t want to have to start styling it. If material design is your thing, that one is a solution.

Then there’s Alertify JS, which is a lightweight, snazzy little bit of code that nails the alerting / notification requirement perfectly. Only there’s a problem.

Alertify JS is an immediately-invoked function function expression (IIFE), which is cool in so much as it “just works”. But it’s not so cool in that I need to hook this up using Redux and I couldn’t figure out a way to make it work how I wanted.

The situation I have is that I want to dispatch a new action every time I need to display a notification. The action would hit the reducer, which would update the state. The state would flow down into my notification component and render a nice notification.

Alertify did not play well with this. As an IIFE, where could I put the alertify.log(‘some message’); method in a way that makes sense to be powered by props? If anywhere, it made most sense to put the call in the reducer switch statement. But that’s not redux.

So that was enough to have ruled out both React Toolbox, and Alertify JS. Onwards.

It boiled down to either React Notifications, or the React Notification System. Neither are pre-configured for Redux. Both fit the component / props requirement though.

Ultimately, I went with the React Notification System, simply as the styling looked like what I wanted. And I very much dislike doing any styling if I really can avoid it.

Ok, so some code.

import React, { PropTypes } from 'react';
import SomeOtherComponent from '../containers/SomeOtherComponent';
import NotificationContainer from '../containers/Notification';

const App = (props) => {
  return (
      <div className="body">
        <SomeOtherComponent props/>
        <NotificationContainer props/>
      </div>
  );
};

export default App;

First thing, add the Notification container on the top level component.

export const ADD_NOTIFICATION = 'ADD_NOTIFICATION';

The action type / constant that matches this action.

import { ADD_NOTIFICATION } from '../constants/ActionTypes';

export function addNotification(message, level) {
  return {
    type: ADD_NOTIFICATION,
    message,
    level
  };
}

Declaring the add notification action function is really straightforward. Just like any other redux action, a simple function containing a payload of data.

import {
  ADD_NOTIFICATION
} from '../constants/ActionTypes';

export default function notification(state = {}, action) {
  switch (action.type) {
    case ADD_NOTIFICATION:
      return Object.assign({}, state, {
        message: action.message,
        level: action.level
      });

    default:
      console.debug('notification reducer :: hit default', action.type);
      return state;
  }
}

The reducer is also very straightforward. As mentioned, I want a component that receives some props (that can change by way of a redux managed state update), and then display a new notification accordingly.

Also, don’t forget to enable this reducer by adding it to the rootReducer :

import { combineReducers } from 'redux';
import {routerReducer} from 'react-router-redux';
import otherReducer from './otherReducer';
import notification from './notificationReducer';

const rootReducer = combineReducers({
  routing: routerReducer,
  otherReducer,
  notification
});

export default rootReducer;

At this stage, I am not concerned with different types of notifications, or doing anything particularly fancy at all. Just some text, and a level, which is React Notification System’s terminology for success, info, warning, etc.

Notice also, the console.debug  statement on the default switch  case? That’s because of this.

import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { addNotification } from '../actions/notificationActions';
import NotificationSystem from 'react-notification-system';

class NotificationContainer extends Component {

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    this.notificationSystem = this.refs.notificationSystem;
  }

  componentWillReceiveProps(newProps) {
    const { message, level } = newProps.notification;
    this.notificationSystem.addNotification({
      message,
      level
    });
  }

  render() {
    return (
      <NotificationSystem ref="notificationSystem" />
    );
  }
}

function mapStateToProps(state) {
  return {
    notification: state.notification
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators({
      addNotification
    }, dispatch)
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(NotificationContainer);

The real hard work of actually rendering a notification is given to React Notification System. I just need a way of adding a new notification whenever this component receives some new props.

Anyway, it all works really nicely so far.

I have a variety of actions that make use of fetch, and I’m doing this (simplified to show the dispatching):

return fetch('https://api.some-site.com/whatever.json', { method: 'POST' })
  .then(res => {
    dispatch(addedSomethingElse(somethingElse, res));
    dispatch(addNotification('happy days', 'success'));
  })
  .catch(err => {
    dispatch(failedAddingSomethingElse(somethingElse, err));
    dispatch(addNotification('it went horribly wrong', 'error'));
  });

I’m incredibly new to ES6, React, Redux, and most other parts of the ecosystem, so:

  • if I used any terminology incorrectly;
  • could improve my practices in any way;
  • or did this all wrong!

Then please do leave a comment and let me know 🙂

 

Published by

Code Review

CodeReviewVideos is a video training site helping software developers learn Symfony faster and easier.

12 thoughts on “Notifications with React and Redux”

  1. Thanks for this tutorial. It really helped me design a redux-connected notification system.

  2. Thank you! This tutorial is really helped me! I think, you can make an redux extension for React Notification System. Later I’ll try the same method to adjust work with React Alert.

  3. Hello, I just wanted to ask why aren’t you recommending easier to implement options like https://reactstrap.github.io/components/alerts/ . Like I’m jot curious…bcoz I tried the above examples like
    React Toolbox – Snackbar component
    Igor Prado’s React Notification System
    Patrick Burtchaell’s React Notifications
    but either they are bit more complicated than the link I posted or giving some errors with my boilerplate.

    1. Hi Tripti rawat,

      I’ve used Reactstrap for quite a while now, and I like it. One thing I found, however, is that I didn’t really need it. For almost every project I used Reactstrap with, I ended up removing it and just using raw Bootstrap 4 instead. Why? One less project dependency.

      Why not use their alerts? Well, the three notification systems you mention, as well as the one I use personally, all do pop up / toast style notifications. Reactstrap / plain bootstrap alerts are ‘static’. I do use Bootstrap’s alerts, but for example, when logging in I think it’s nicer to show a toast notification that says “welcome back {username}” and then disappears, rather than render something static that the user has to manually dismiss. Personal preference I suppose.

      As ever, use whatever you feel most comfortable with. I’m not saying I’m right, I just share what works for me.

      1. It’s funny that I came back to this post with the same experience 😀 . Now that my use cases are increasing, I encountered the static display problem. So I’m back to square 1. Thanks for replying.

      2. I’m new with reactjs and redux and I use reactstrap to the app that I’m trying to build for practice. Though I like to use existing notification as you mentioned in your post, I decided to use the static reactstrap’s Alert component. Everything’s work as I expected, manual and auto (using settimeout method) dismissal. Now, I wanted to make it multiple notification like React Notification System

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.