DEV Community

James Parker
James Parker

Posted on

Advanced Notification System with Reapop and Redux in React

Reapop is a powerful, Redux-based notification system for React applications. It provides a flexible and scalable approach to managing notifications using Redux for state management, making it ideal for complex applications that need centralized notification handling. This guide walks through advanced usage of Reapop with React and Redux, including custom configurations, middleware integration, and complex notification patterns. This is part 36 of a series on using Reapop with React.

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Redux and React-Redux installed and configured
  • Basic knowledge of Redux (actions, reducers, store)
  • Understanding of React hooks (useSelector, useDispatch)
  • Familiarity with JavaScript/TypeScript

Installation

Install Reapop and Redux dependencies:

npm install reapop react-redux redux
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add reapop react-redux redux
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add reapop react-redux redux
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "reapop": "^4.0.0",
    "react-redux": "^8.0.0",
    "redux": "^4.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

Set up Redux store with Reapop reducer. First, create the Redux store:

// src/store/index.js
import { createStore, combineReducers } from 'redux';
import { reducer as notificationsReducer } from 'reapop';

const rootReducer = combineReducers({
  notifications: notificationsReducer
});

export const store = createStore(rootReducer);
Enter fullscreen mode Exit fullscreen mode

Now set up the provider and notification system in your main entry file:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store';
import { NotificationsSystem } from 'reapop';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
      <NotificationsSystem />
    </Provider>
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

First Example / Basic Usage

Let's create a simple notification component. Create a new file src/NotificationExample.jsx:

// src/NotificationExample.jsx
import React from 'react';
import { useDispatch } from 'react-redux';
import { notify } from 'reapop';

function NotificationExample() {
  const dispatch = useDispatch();

  const showSuccess = () => {
    dispatch(notify({
      title: 'Success!',
      message: 'Operation completed successfully.',
      status: 'success',
      dismissible: true,
      dismissAfter: 3000
    }));
  };

  const showError = () => {
    dispatch(notify({
      title: 'Error!',
      message: 'Something went wrong.',
      status: 'error',
      dismissible: true,
      dismissAfter: 5000
    }));
  };

  const showWarning = () => {
    dispatch(notify({
      title: 'Warning!',
      message: 'Please review your input.',
      status: 'warning',
      dismissible: true,
      dismissAfter: 4000
    }));
  };

  const showInfo = () => {
    dispatch(notify({
      title: 'Info',
      message: 'Here is some information.',
      status: 'info',
      dismissible: true,
      dismissAfter: 3000
    }));
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Notification Examples</h2>
      <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
        <button onClick={showSuccess}>Success</button>
        <button onClick={showError}>Error</button>
        <button onClick={showWarning}>Warning</button>
        <button onClick={showInfo}>Info</button>
      </div>
    </div>
  );
}

export default NotificationExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import NotificationExample from './NotificationExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <NotificationExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Understanding the Basics

Reapop uses Redux for state management where:

  • notify action: Creates a new notification
  • dismissNotification action: Dismisses a specific notification
  • dismissNotifications action: Dismisses all notifications
  • NotificationsSystem: Component that renders all notifications
  • Redux Store: Centralized state management for all notifications

Key concepts for advanced usage:

  • Redux Integration: Notifications are managed through Redux store
  • Action Creators: Use notify action creator to create notifications
  • Middleware: Can integrate with Redux middleware for async operations
  • Custom Components: Customize notification appearance and behavior
  • Positioning: Configure notification positions and stacking

Here's an example with custom configuration:

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { reducer as notificationsReducer, setUpNotifications } from 'reapop';
import thunk from 'redux-thunk';

// Configure notifications
setUpNotifications({
  defaultProps: {
    position: 'top-right',
    dismissible: true,
    dismissAfter: 5000
  }
});

const rootReducer = combineReducers({
  notifications: notificationsReducer
});

export const store = createStore(rootReducer, applyMiddleware(thunk));
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive notification system with custom hooks, middleware integration, and advanced features:

// src/hooks/useNotifications.js
import { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import { notify, dismissNotification } from 'reapop';

export const useNotifications = () => {
  const dispatch = useDispatch();

  const showSuccess = useCallback((title, message, options = {}) => {
    return dispatch(notify({
      title,
      message,
      status: 'success',
      dismissible: true,
      dismissAfter: 3000,
      ...options
    }));
  }, [dispatch]);

  const showError = useCallback((title, message, options = {}) => {
    return dispatch(notify({
      title,
      message,
      status: 'error',
      dismissible: true,
      dismissAfter: 5000,
      ...options
    }));
  }, [dispatch]);

  const showWarning = useCallback((title, message, options = {}) => {
    return dispatch(notify({
      title,
      message,
      status: 'warning',
      dismissible: true,
      dismissAfter: 4000,
      ...options
    }));
  }, [dispatch]);

  const showInfo = useCallback((title, message, options = {}) => {
    return dispatch(notify({
      title,
      message,
      status: 'info',
      dismissible: true,
      dismissAfter: 3000,
      ...options
    }));
  }, [dispatch]);

  const showLoading = useCallback((title, message) => {
    return dispatch(notify({
      title,
      message,
      status: 'loading',
      dismissible: false,
      dismissAfter: 0
    }));
  }, [dispatch]);

  const dismiss = useCallback((notificationId) => {
    dispatch(dismissNotification(notificationId));
  }, [dispatch]);

  return {
    showSuccess,
    showError,
    showWarning,
    showInfo,
    showLoading,
    dismiss
  };
};
Enter fullscreen mode Exit fullscreen mode

Now create an advanced notification system component:

// src/AdvancedNotificationSystem.jsx
import React, { useState } from 'react';
import { useNotifications } from './hooks/useNotifications';
import { useDispatch } from 'react-redux';
import { dismissNotifications } from 'reapop';

function AdvancedNotificationSystem() {
  const { showSuccess, showError, showWarning, showInfo, showLoading, dismiss } = useNotifications();
  const dispatch = useDispatch();
  const [formData, setFormData] = useState({
    title: '',
    message: '',
    status: 'success'
  });

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (!formData.title || !formData.message) {
      showError('Validation Error', 'Please fill in all fields.');
      return;
    }

    const options = {
      position: 'top-right',
      dismissible: true
    };

    switch (formData.status) {
      case 'success':
        showSuccess(formData.title, formData.message, options);
        break;
      case 'error':
        showError(formData.title, formData.message, options);
        break;
      case 'warning':
        showWarning(formData.title, formData.message, options);
        break;
      case 'info':
        showInfo(formData.title, formData.message, options);
        break;
      default:
        showInfo(formData.title, formData.message, options);
    }

    setFormData({ title: '', message: '', status: 'success' });
  };

  const simulateApiCall = async () => {
    const loadingId = showLoading('Processing', 'Processing your request...');

    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 2000));

      dismiss(loadingId);
      showSuccess('Success', 'Operation completed successfully!');
    } catch (error) {
      dismiss(loadingId);
      showError('Error', 'Failed to complete operation. Please try again.');
    }
  };

  const showActionNotification = () => {
    const notificationId = showWarning('Action Required', 'Do you want to proceed?', {
      dismissAfter: 0,
      buttons: [
        {
          name: 'Yes',
          primary: true,
          onClick: () => {
            dismiss(notificationId);
            showSuccess('Confirmed', 'Action confirmed.');
          }
        },
        {
          name: 'No',
          onClick: () => {
            dismiss(notificationId);
            showInfo('Cancelled', 'Action cancelled.');
          }
        }
      ]
    });
  };

  const clearAllNotifications = () => {
    dispatch(dismissNotifications());
  };

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h1>Advanced Notification System</h1>

      <form onSubmit={handleSubmit} style={{ marginBottom: '20px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Title *
          </label>
          <input
            type="text"
            name="title"
            value={formData.title}
            onChange={handleInputChange}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
            required
          />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Message *
          </label>
          <textarea
            name="message"
            value={formData.message}
            onChange={handleInputChange}
            rows={3}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box',
              resize: 'vertical'
            }}
            required
          />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Status
          </label>
          <select
            name="status"
            value={formData.status}
            onChange={handleInputChange}
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
          >
            <option value="success">Success</option>
            <option value="error">Error</option>
            <option value="warning">Warning</option>
            <option value="info">Info</option>
          </select>
        </div>

        <button
          type="submit"
          style={{
            width: '100%',
            padding: '10px',
            backgroundColor: '#007bff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer',
            fontSize: '16px'
          }}
        >
          Show Notification
        </button>
      </form>

      <div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
        <button
          onClick={simulateApiCall}
          style={{
            padding: '10px',
            backgroundColor: '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Simulate API Call
        </button>
        <button
          onClick={showActionNotification}
          style={{
            padding: '10px',
            backgroundColor: '#ffc107',
            color: 'black',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Show Action Notification
        </button>
        <button
          onClick={clearAllNotifications}
          style={{
            padding: '10px',
            backgroundColor: '#dc3545',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Clear All Notifications
        </button>
      </div>
    </div>
  );
}

export default AdvancedNotificationSystem;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import AdvancedNotificationSystem from './AdvancedNotificationSystem';
import './App.css';

function App() {
  return (
    <div className="App">
      <AdvancedNotificationSystem />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Update your store configuration for better setup:

// src/store/index.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { reducer as notificationsReducer, setUpNotifications } from 'reapop';
import thunk from 'redux-thunk';

// Configure notifications
setUpNotifications({
  defaultProps: {
    position: 'top-right',
    dismissible: true,
    dismissAfter: 5000,
    allowHTML: false
  }
});

const rootReducer = combineReducers({
  notifications: notificationsReducer
});

export const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
Enter fullscreen mode Exit fullscreen mode

Common Issues / Troubleshooting

  1. Notifications not displaying: Ensure NotificationsSystem is rendered in your app and Provider wraps your application with the Redux store.

  2. Redux store not configured: Make sure you've added the notifications reducer to your Redux store using combineReducers.

  3. Actions not working: Ensure you're using useDispatch from react-redux to dispatch notification actions. The notify action creator must be imported from reapop.

  4. Notifications not dismissing: Check the dismissAfter property. Set it to a number (milliseconds) for auto-dismissal, or 0 for persistent notifications. Use dismissible: true to allow manual dismissal.

  5. Custom styling not working: Reapop allows custom notification components. You can override the default notification component by configuring it in setUpNotifications.

  6. Multiple notifications stacking: Reapop handles multiple notifications automatically. They will stack based on the position setting. Use dismissNotifications() to clear all notifications at once.

Next Steps

Now that you have an advanced understanding of Reapop:

  • Explore Redux middleware integration for async notifications
  • Learn about custom notification components
  • Implement notification persistence and storage
  • Add notification queues and limits
  • Integrate with Redux DevTools for debugging
  • Learn about other notification libraries (notistack, react-toastify)
  • Check the official repository: https://github.com/LouisBarranqueiro/reapop
  • Look for part 37 of this series for more advanced topics

Summary

You've successfully integrated Reapop into your React application with Redux for advanced notification management. Reapop provides a scalable, Redux-based solution for displaying notifications with centralized state management and extensive customization options.

SEO Keywords

reapop
React Redux notifications
reapop tutorial
React notification system
reapop installation
React Redux toast
reapop example
React notification library
reapop setup
React Redux alerts
reapop customization
React notification hooks
reapop middleware
React notification state
reapop getting started

Top comments (0)