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.
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.