Simple Custom Alerts In A React Application

Alexander Paterson
|
Posted over 6 years ago
|
6 minutes
Simple Custom Alerts In A React Application
Another one of those features every app needs: alerts

I have a very simple way of creating and showing alerts in my React applications. I simply fix an alert container component to the top-right of my application, and this component renders an alert component for each object in the global redux state's alerts property. An alert object in the state.alerts array has three properties: an id, some text, and a style. The id can be used to dispatch an action to dismiss the alert and style is just an additional class name for the alert component.

Custom React Native Alerts

Showing an alert is as simple as dispatching an action. I have a git repository/npm package that contains the code I normally use, along with an example application. Here, I'm going to go through the code and explain how to use/recreate it.

Reducer

The reducer is set up as follows. The alerts reducer is just an array of alert objects, which actions add and remove.

// reducers/index.js

import {combineReducers} from 'redux';
import uuid from 'node-uuid';


var alertsReducer = (state = [], action) => {
  switch (action.type) {

    case 'ADD_ALERT':
      return [
        ...state,
        {
          text: action.text,
          style: action.style,
          id: uuid()
        }
      ];

    case 'REMOVE_ALERT':
      return state.filter((alert) => {
        if (alert.id === action.id ) {
          return false;
        } else {
          return true;
        }
      });

    default:
      return state;
  }
};

export default combineReducers({
  alerts: alertsReducer
})

Actions

These actions should be self-explanatory. 

// actions/index.js

var addAlert = (text, style) => {
  return {
    type: 'ADD_ALERT',
    text,
    style
  };
};

var removeAlert = (id) => {
  return {
    type: 'REMOVE_ALERT',
    id
  };
};

module.exports = {
  addAlert: addAlert,
  removeAlert: removeAlert
}

Component

Here's the AlertsOverlayComponent, which is the container that displays our alerts. In my source code this component isn't connected to redux, so that we have the option to pass in the alerts as a prop directly.

// components/AlertsOverlayComponent.jsx

import React from 'react';


var AlertsOverlayComponent = React.createClass({
  render: function() {
    var {alerts, children, style} = this.props;

    var renderAlerts = function() {
      return alerts.map(function(alert) {
        return React.cloneElement(children, {alert: alert, key: alert.id});
      });
    }

    return (
      <div className="react-alerts-overlay-component-container">
        {renderAlerts()}
      </div>
    );
  }
});

module.exports = AlertsOverlayComponent;

The alert component itself is connected to redux so that it can dispatch its own dismissal when clicked.

// components/Alert.jsx

import React from 'react';
import {connect} from 'react-redux';


var Alert = React.createClass({
  removeAlert: function() {
    var {dispatch, alert} = this.props;
    dispatch(removeAlert(alert.id));
  },
  render: function() {
    var {alert, style} = this.props;
    return (
      <div className={alert.style} key={alert.id} onClick={this.removeAlert} style={style}>
        <div className="flex">
          <div>
            {alert.text}
          </div>
          <div className="settings-action">
            <i className="fa fa-close"></i>
          </div>
        </div>
      </div>
    );
  }
});

module.exports = connect()(Alert);

Usage

This is code from the example/ directory of my react-alerts-overlay-component. Here, Main is a component that's connected to redux, and it passes alerts to AlertsOverlayComponent as a prop. In most cases it would make more sense to directly connect AlertsOverlayComponet to redux using the same mapAlertsToProps that we see here. 

// components/Main.jsx

import React from 'react';
import {connect} from 'react-redux';

var Alert = require('./Alert')
var AlertsOverlayComponent = require('./AlertsOverlayComponent')


export var Main = React.createClass({
  componentDidMount: function() {
    var {dispatch} = this.props;
    dispatch(addAlert("Test alert!", "success"));
  },
  render: function() {
    var {alerts} = this.props;
    return (
      <div>
        <AlertsOverlayComponent alerts={alerts}>
          <Alert />
        </AlertsOverlayComponent>
      </div>
    );
  }
});

var mapAlertsToProps = (state) => {
  return {
    alerts: state.alerts
  }
}

module.exports = connect(mapAlertsToProps)(Main);

 And for good measure, here's the application code, none of which is specific to what we're doing here. 

// app.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import {compose, createStore, applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk';

import reducer from '../reducers';
import Main from './components/Main';


var configureStore = (initialState = {}) => {
  const store = createStore(reducer, initialState, compose(
    applyMiddleware(thunk),
    window.devToolsExtension ? window.devToolsExtension() : f => f
  ));
  return store;
};
var store = configureStore();


ReactDOM.render(
  <Provider store={store}>
    <Main />
  </Provider>,
  document.getElementById('app')
);

If you have any troubles implementing this yourself, just ask a question in the comments. This is all very standard react/redux stuff.



-->
ALEXANDER
PATERSON