You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现React全局可调用的自定义Notification工具函数(支持非React场景)

实现可全局调用的Notification工具函数

1. 实现全局队列与工具函数

创建单独文件notificationUtils.js,作为非React场景和React组件的通信桥梁:

// 全局队列,存储待显示的通知
const notificationQueue = [];

// 供外部调用的工具函数
export function showNotification(message, onClose) {
  notificationQueue.push({
    id: Date.now(), // 唯一标识每个通知
    message,
    onClose: onClose || (() => {})
  });
}

export { notificationQueue };

2. 实现顶层Notification容器组件

创建NotificationContainer.jsx,负责渲染通知、处理自动关闭和手动关闭逻辑:

import { useState, useEffect, useRef } from 'react';
import Notification from './Notification';
import { notificationQueue } from './notificationUtils';

export default function NotificationContainer() {
  const [notifications, setNotifications] = useState([]);
  const resolveRef = useRef({}); // 存储每个通知的resolve函数,用于手动关闭

  useEffect(() => {
    // 处理队列中的通知
    const processQueue = async () => {
      while (notificationQueue.length > 0) {
        const notification = notificationQueue.shift();
        const { id, message, onClose } = notification;

        // 将通知加入渲染列表
        setNotifications(prev => [...prev, { id, message }]);

        // 等待5秒或手动关闭
        await new Promise(resolve => {
          resolveRef.current[id] = resolve;
          // 设置自动关闭定时器
          const timer = setTimeout(() => {
            resolve();
            delete resolveRef.current[id];
          }, 5000);
        });

        // 移除通知并执行关闭回调
        setNotifications(prev => prev.filter(n => n.id !== id));
        onClose();
      }
    };

    // 初始处理队列
    processQueue();

    // 监听队列变化,有新通知时重新处理
    const observer = new MutationObserver(() => {
      if (notificationQueue.length > 0) {
        processQueue();
      }
    });
    observer.observe(notificationQueue, { childList: true });

    return () => {
      observer.disconnect();
      // 卸载时清除所有待处理通知
      Object.values(resolveRef.current).forEach(resolve => resolve());
    };
  }, []);

  // 处理手动关闭
  const handleClose = (id) => {
    if (resolveRef.current[id]) {
      resolveRef.current[id]();
    }
  };

  return (
    <div className="notification-container" style={{
      position: 'fixed',
      top: '20px',
      right: '20px',
      zIndex: 9999,
      display: 'flex',
      flexDirection: 'column',
      gap: '10px'
    }}>
      {notifications.map(notification => (
        <Notification
          key={notification.id}
          message={notification.message}
          close={() => handleClose(notification.id)}
        />
      ))}
    </div>
  );
}

3. 在应用顶层挂载容器

在index.js或App.js的最外层挂载容器,确保它能全局渲染通知:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import NotificationContainer from './NotificationContainer';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <NotificationContainer />
    <App />
  </React.StrictMode>
);

4. 任意位置调用工具函数

现在可以在React组件、redux actions、sagas甚至普通工具函数中直接调用:

// 在redux action中调用
export const fetchData = () => async (dispatch) => {
  try {
    const data = await api.fetchData();
    dispatch({ type: 'FETCH_SUCCESS', payload: data });
    showNotification('数据获取成功!');
  } catch (error) {
    dispatch({ type: 'FETCH_ERROR', payload: error.message });
    showNotification('数据获取失败,请重试', () => {
      console.log('用户关闭了通知');
    });
  }
};

// 在saga中调用
function* fetchDataSaga() {
  try {
    const data = yield call(api.fetchData);
    yield put({ type: 'FETCH_SUCCESS', payload: data });
    showNotification('数据获取成功!');
  } catch (error) {
    yield put({ type: 'FETCH_ERROR', payload: error.message });
    showNotification('数据获取失败,请重试');
  }
}

// 在普通函数中调用
function handleFormSubmit() {
  showNotification('表单提交成功');
}

关键逻辑说明

  • 全局队列:作为非React代码和React组件的中间层,外部调用工具函数时将通知信息加入队列。
  • 顶层容器:监听队列变化,异步处理每个通知,负责渲染、自动关闭和手动关闭逻辑。
  • Promise与resolveRef:用Promise控制通知显示时长,resolveRef存储每个通知的resolve函数,实现手动关闭时提前结束Promise并移除通知。

内容的提问来源于stack exchange,提问作者marcus-linmarkson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:40:59