Нотифікації in React

Нотифікації in React

  • 18 квітня
  • читати 15 хв
Володимир Шайтан
Володимир Шайтан Senior Full Stack Developer у UKEESS Software House, Викладач Комп'ютерної школи Hillel.
Семен Захаров
Семен Захаров Junior Software Developer у Ratifire

У цій статті будемо розбиратися з темою реалізації нотифікацій у вебпроєктах, а також як правильно розробляти функціонал нотифікації у вебдодатках написаних на React. Тепер до головного, почнемо з простого.

Нотифікації — це короткі повідомлення, які з’являються у додатках для інформування користувачів про події або зміни. Вони виконують важливу функцію у взаємодії з користувачами, допомагаючи зробити інтерфейс зрозумілим і зручним.

Основна мета нотифікацій — залучати увагу користувача в потрібний момент і передавати йому цінну інформацію без зайвих зусиль.

ЧОМУ ЦЕ ВАЖЛИВО?

Річ у тому що функціонал нотифікацій досить сильно підвищує UX і допомагає користувачу краще розуміти, що він робить. Це досить важливо, особливо коли функції, котрі ви розробляєте, комплексні. Задача проєкту — бути корисним для користувача, тому ми повинні пояснювати користувачу, що він робить і як тими функціями користуватися.

ЩО ТАКЕ UX (USER EXPERIENCE)?

Це досвід, який користувач отримує під час взаємодії з продуктом, вебсайтом або додатком. Це не лише про те, як щось виглядає, а й про те, наскільки зручно, інтуїтивно й ефективно користувач може досягти своєї мети під час взаємодії з інтерфейсом.

З причин описаним вище, типовою задачею, майже на будь-якому проєкті є розробка функціоналу нотифікацій, котрі будуть супроводжувати користувача про те, що він робить і на що варто звернути увагу.

ОФЛАЙН-НОТИФІКАЦІЇ

Тут усе дуже цікаво, адже такі нотифікації будуть приходити користувачу безпосередньо в його операційну систему і далі сама система буде його інформувати. Важливо зрозуміти, що я говорю не про email-листи чи sms, а мова йде саме про push-нотифікації, до котрих ми так звикли користуючись мобільними телефонами й додатками.

І, так, можна відправляти push-нотифікації з вебдодатка відразу на телефон користувача, тільки треба розібратись, як це роботи. Це не дуже важко, але досить цікаво. Ну і звісно, мова йде не тільки про мобільні телефони, але й про комп'ютери. Тобто push-нотифікації так само можна надсилати й на інші пристрої, в будь-якому випадку працювати це буде майже однаково.

Далі трохи розкажу і покажу як налаштувати push-повідомлення на своєму проєкті. Тут нам треба буде трохи розібратись з ServiceWorker, бо вся робота проходитиме через нього, а в кінці я прикріплю статтю про ServiceWorker.

НАЛАШТУВАННЯ PUSH-ПОВІДОМЛЕНЬ

Service Worker — це спеціальний скрипт, що працює у фоновому режимі та не залежить від сторінки, на якій перебуває користувач. Оскільки це фоновий скрипт, то він може працювати та виконувати операції й тоді, коли користувач не переглядає вебсайт.

Для початку нам треба зареєструвати ServiceWorker:

if ('serviceWorker' in navigator) {
   window.addEventListener('load', function() {
       navigator.serviceWorker.register('/service-worker.js')
           .then(function(registration) {
               // Реєстрація успішна
               console.log('ServiceWorker registration successful with scope: ', registration.scope);
           }, function(err) {
               // Реєстрація провалилася
               console.log('ServiceWorker registration failed: ', err);
           });
   });
}

Далі слід попросити користувача підписатись на push-повідомлення. Так-так, це найбільш правильний підхід.

document.getElementById('subscribe').addEventListener('click', function() {
   if ('serviceWorker' in navigator) {
       navigator.serviceWorker.ready.then(function(registration) {
           registration.pushManager.subscribe({
               userVisibleOnly: true,
               // Використовуйте власний вебключ для push-повідомлень
               applicationServerKey: 'YOUR_WEB_PUSH_KEY'
           }).then(function(subscription) {
               console.log('User is subscribed:', subscription);
           }).catch(function(err) {
               console.log('Failed to subscribe the user: ', err);
           });
       });
   }
});

Після цього нам потрібно додати обробник для push-повідомлення.

self.addEventListener('push', function(event) {
   const options = {
       body: 'Це push-повідомлення!',
       icon: 'images/icon.png',
       badge: 'images/badge.png'
   };
   event.waitUntil(
       self.registration.showNotification('Push Notification', options)
   );
});

НОТАТКИ

  1. Ви маєте згенерувати власний вебключ для push-повідомлень, який буде використовуватися в applicationServerKey у scripts/push.js.
  2. Для використання push-повідомлень вам також потрібно буде налаштувати backend-сервер, який відправлятиме push-повідомлення до підписаних користувачів.
  3. Повний приклад демонстраційного проєкту доступний за посиланням.

РОЗУМІННЯ НОТИФІКАЦІЙ У ВЕБДОДАТКАХ

Говорячи про звичайні online-нотифікації, котрі ми бачимо на кожному сайті, хотілося би для початку розбити їх на типи. Оскільки у вебдодатку ми маємо змогу керувати тзовнішнім виглядом, звуками, анімаціями нотифікацій, тут, звісно, контролю над процесом у нас набагато більше.

Типи нотифікацій

  1. Інформаційні:
    • Використовуються для загальних повідомлень, які не потребують негайної дії.
    • Приклад: «Ваш профіль оновлено успішно».
  2. Помилки:
    • Повідомляють про проблеми, які потребують уваги користувача.
    • Приклад: «Не вдалося зберегти дані. Спробуйте ще раз».
  3. Успіхи:
    • Відображають успішне завершення дії.
    • Приклад: «Ваше замовлення оформлено».
  4. Попередження:
    • Використовуються для запобігання помилкам або важливих дій.
    • Приклад: «Ваш акаунт майже заповнив доступне місце. Додайте новий тариф».

Де використовуються нотифікації?

Нотифікації застосовуються в багатьох частинах вебдодатків:

  1. Форми:
    • Інформування про успіхи чи помилки при відправці даних.
  2. Процеси оплати:
    • Підтвердження успішного платежу.
  3. Інтерактивні елементи:
    • Повідомлення про завершення дій (наприклад, додавання до кошика).
  4. Оновлення даних:
    • Інформація про статуси операцій, наприклад, оновлення профілю.

Що робить нотифікації ефективними?

  1. Чіткість і лаконічність:
    • Повідомлення мають бути короткими та зрозумілими.
    • Наприклад: «Файл завантажено» замість «Процес завантаження файлу завершено успішно».
  2. Видимість:
    • Нотифікації мають бути помітними, але не заважати користувачу.
    • Приклад: Використання легких тіней чи анімації для появи.
  3. Час показу:
    • Нотифікації повинні автоматично закриватися через 3–5 секунд, якщо це не критичне повідомлення.
  4. Можливість закриття:
    • Додай кнопку «Закрити» або хрестик для зручності.

РЕАЛІЗАЦІЯ НОТИФІКАЦІЙ У REACT

У цьому розділі ми виділимо 3 підходи, котрі будуть достатньо сильно відрізнятися між собою. Ціль цього — показати, що і коли краще використовувати. Найпростіший шлях не завжди поганий, а забивати цвяхи кувалдою, може бути не overkill.

1️⃣ Локальний стан у компоненті (useState)

У цьому підході ми використовуємо useState всередині одного компонента, щоб зберігати й відображати нотифікації. Це найпростіший спосіб, який не вимагає додаткових інструментів.

import React, { useState } from 'react';

const App = () => {
   const [notification, setNotification] = useState(null);

   const showNotification = (message, type) => {
       setNotification({ message, type });
       setTimeout(() => setNotification(null), 3000);
   };

   return (
       <div>
           <h1>Simple Notification Example</h1>
           <button onClick={() => showNotification('This is an info message', 'info')}>Show Info</button>
           <button onClick={() => showNotification('This is a success message', 'success')}>Show Success</button>
           <button onClick={() => showNotification('This is an error message', 'error')}>Show Error</button>

           {notification && (
               <div className={`notification ${notification.type}`}>
                   {notification.message}
               </div>
           )}
       </div>
   );
};

export default App;

Чому це добре?

  1. Швидка реалізація: мінімум коду, зрозуміла логіка.
  2. Простота: не потрібно контекстів, зовнішніх бібліотек чи складних патернів.
  3. Локальність: нотифікації працюють лише в конкретному компоненті.

Чому це погано?

  1. Обмеження у масштабах: неможливо відправити нотифікацію з іншого компонента.
  2. Дублювання коду: якщо потрібно нотифікації у кількох місцях, доведеться дублювати логіку.
  3. Важко підтримувати: з ростом додатка важко керувати нотифікаціями.

Коли вибирати?

  • Маленькі проєкти або MVP.
  • Нотифікації потрібні лише в одному компоненті.
  • Мінімальні вимоги до логіки.

Висновок: це як використання кувалди для забивання маленького цвяха. Працює чудово, тільки якщо задачі прості. Але як тільки з'являються глобальні вимоги — це вже не підходить.

2️⃣ Централізоване управління (React Context API)

Створюється глобальний контекст за допомогою React Context API, який забезпечує доступ до функцій для додавання, видалення і відображення нотифікацій у будь-якому компоненті.

NotificationContext.js

import React, { createContext, useContext, useState } from 'react';

const NotificationContext = createContext();

export const useNotification = () => useContext(NotificationContext);

export const NotificationProvider = ({ children }) => {
   const [notifications, setNotifications] = useState([]);

   const addNotification = (message, type = 'info') => {
       const id = Date.now();
       setNotifications((prev) => [...prev, { id, message, type }]);
       setTimeout(() => removeNotification(id), 3000);
   };

   const removeNotification = (id) => {
       setNotifications((prev) => prev.filter((notif) => notif.id !== id));
   };

   return (
       <NotificationContext.Provider value={{ addNotification }}>
           {children}
           <div className="notification-container">
               {notifications.map((notif) => (
                   <div key={notif.id} className={`notification ${notif.type}`}>
                       {notif.message}
                   </div>
               ))}
           </div>
       </NotificationContext.Provider>
   );
};

App.jsx

import React from 'react';
import { NotificationProvider, useNotification } from './NotificationContext';

const AppContent = () => {
   const { addNotification } = useNotification();

   return (
       <div>
           <h1>Centralized Notification Example</h1>
           <button onClick={() => addNotification('Info message', 'info')}>Show Info</button>
           <button onClick={() => addNotification('Success message', 'success')}>Show Success</button>
           <button onClick={() => addNotification('Error message', 'error')}>Show Error</button>
       </div>
   );
};

const App = () => (
   <NotificationProvider>
       <AppContent />
   </NotificationProvider>
);

export default App;

Чому це добре?

  1. Глобальне керування: нотифікацію можна викликати з будь-якого місця в додатку.
  2. Єдине джерело правди: всі нотифікації зберігаються у єдиному сховищі.
  3. Легше підтримувати: одна точка контролю для всіх нотифікацій.

Чому це погано?

  1. Складність для новачків: потрібно розуміти, як працює Context API.
  2. Перевантаження контексту: велика кількість логіки у контексті може призводити до зайвих ререндерів.
  3. Обмежена гнучкість: немає готових анімацій чи складних налаштувань.

Коли вибирати?

  • Середні додатки з помірними вимогами до нотифікацій.
  • Коли потрібне глобальне керування, але немає потреби у складній кастомізації.
  • Коли важливо мати централізований контроль над повідомленнями.

Висновок: це як універсальний молоток — він підходить для багатьох задач, але іноді бракує додаткових функцій, як у спеціалізованих інструментах.

3️⃣ Використання зовнішньої бібліотеки (React-Toastify)

Бібліотека React-Toastify надає готовий інтерфейс для роботи з нотифікаціями: різні типи сповіщень, гнучке налаштування, позиціюнування, анімації.

import React from 'react';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const App = () => {
   const notify = (type) => {
       if (type === 'success') toast.success('This is a success message');
       if (type === 'error') toast.error('This is an error message');
       if (type === 'info') toast.info('This is an info message');
   };

   return (
       <div>
           <h1>React-Toastify Example</h1>
           <button onClick={() => notify('success')}>Show Success</button>
           <button onClick={() => notify('error')}>Show Error</button>
           <button onClick={() => notify('info')}>Show Info</button>
           <ToastContainer />
       </div>
   );
};

export default App;

Чому це добре?

  1. Швидка інтеграція: впроваджується за лічені хвилини.
  2. Гнучкість: можливість кастомізації, підтримка анімацій, різні позиції на екрані.
  3. Великий функціонал: тайм-аути, кнопки CTA, індивідуальні стилі.
  4. Оптимізація: нотифікації відображаються ефективно без зайвих ререндерів.

Чому це погано?

  1. Залежність: додаткова бібліотека у проєкті.
  2. Розмір бандла: збільшує розмір застосунку.
  3. Оверінжиніринг для дрібних задач: для простих застосунків це може бути надлишковим рішенням.

Коли вибирати?

  • Великі або середні додатки з високими вимогами до UX.
  • Коли потрібні кастомні нотифікації, гнучкість і підтримка різних сценаріїв.
  • Коли важливий швидкий розвиток без «винаходження велосипеда».

Висновок: це як швейцарський ніж — він підходить для будь-якої задачі, має все необхідне і навіть трохи більше.

ВИСНОВОК

Нотифікації — це не просто вікна, що спливають чи маленькі повідомлення, а місток між додатком і користувачем. Вони допомагають інформувати, направляти й залучати людину у взаємодію з продуктом.

Онлайн-нотифікації чудово працюють, коли користувач активно використовує додаток: вони швидко передають інформацію, забезпечують миттєвий зворотний зв'язок і поліпшують загальний досвід взаємодії.

Push-нотифікації, зі свого боку, дозволяють підтримувати зв'язок навіть тоді, коли додаток не відкритий. Вони ідеальні для важливих сповіщень, акцій чи нагадувань, забезпечуючи присутність бренду «поза екраном».

Кожен із підходів — локальний стан, централізоване управління через Context API або використання сторонніх бібліотек, як-от React-Toastify — має свої плюси і мінуси. Важливо вибрати те, що найкраще відповідає масштабам і цілям вашого проєкту.

Головне правило: не ускладнюйте там, де можна зробити просто, і завжди думайте про користувача. Нотифікації повинні допомагати, а не дратувати. 

Рекомендуємо публікації по темі