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

如何实现可实时显示进度的React Snackbar 解决notistack重复弹出问题

实现方案

你的需求完全可以实现,不用额外替换现有依赖,你正在使用的notistack本身就支持同个Snackbar的内容热更新,不会触发新的弹出动画。

基于notistack的修正方案

核心逻辑是给进度类Snackbar设置固定唯一的标识key,notistack检测到已存在同key的Snackbar时,会直接更新它的内容和配置,不会生成新的提示。

修正后的代码示例:

import { useSnackbar } from 'notistack';
import { useState, useEffect } from 'react';

// 给这个进度Snackbar设置固定唯一key,多个任务可以用任务ID作为key区分
const PROGRESS_KEY = 'download_progress';

function DownloadBtn() {
  const { enqueueSnackbar } = useSnackbar();
  const [progress, setProgress] = useState(0);

  // 模拟进度更新
  useEffect(() => {
    if (progress === 0) return;
    // 进度到100%后修改样式,自动关闭
    if (progress >= 100) {
      enqueueSnackbar('下载完成:100%', {
        key: PROGRESS_KEY,
        variant: 'success',
        autoHideDuration: 3000
      });
      setProgress(0);
      return;
    }
    // 实时更新进度,复用同一个Snackbar
    enqueueSnackbar(`当前进度:${progress}%`, {
      key: PROGRESS_KEY,
      variant: 'info',
      autoHideDuration: null, // 进度更新期间不自动关闭
      preventDuplicate: true
    });
    const timer = setTimeout(() => setProgress(p => p + 10), 600);
    return () => clearTimeout(timer);
  }, [progress, enqueueSnackbar]);

  const handleStart = () => setProgress(10);

  return <button onClick={handleStart}>开始下载</button>;
}

适配Redux的实现方案

如果需要用Redux管理全局进度状态,有两种成熟方案可选:

  • 继续使用notistack:把进度状态存在Redux切片中,在全局组件中监听Redux的进度变化,调用enqueueSnackbar传入固定key更新内容即可,接入成本极低,同时支持多任务并行的进度Snackbar展示
  • 使用Material UI原生Snackbar自定义封装:完全自主控制Snackbar的展示逻辑、样式,可自定义加入线性进度条等UI元素,适合定制化需求高的场景。只需在Redux中维护Snackbar的显隐、进度、文案状态,全局组件绑定对应状态即可,所有更新通过dispatch action触发,不会生成新提示。

Redux状态切片示例:

import { createSlice } from '@reduxjs/toolkit';

const snackbarSlice = createSlice({
  name: 'globalSnackbar',
  initialState: {
    open: false,
    message: '',
    progress: 0
  },
  reducers: {
    openProgressSnack: (state) => {
      state.open = true;
      state.progress = 0;
    },
    updateProgress: (state, action) => {
      state.progress = action.payload;
      state.message = `下载进度:${action.payload}%`;
    },
    closeProgressSnack: (state) => {
      state.open = false;
    }
  }
});

export const { openProgressSnack, updateProgress, closeProgressSnack } = snackbarSlice.actions;
export default snackbarSlice.reducer;

内容的提问来源于stack exchange,提问作者Kid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 14:09:03