React Toast组件Sonner使用详解、倒计时扩展

简介

Sonner 是 React 的一个 Toast 组件。

它支持多种类型的提示信息,如成功、错误、信息、警告和加载中,主题定义,可以在页面中显示提示信息。

安装

复制代码
npm install sonner
# or
yarn add sonner

基本使用

Toaster app.jsx 里,也可以放在 layout.jsx 布局文件里,这样全局都可以使用

复制代码
import { Toaster } from "sonner";

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

export default App;

这样组件或者页面,都可以直接使用 toast 方法了

复制代码
import { toast } from "sonner";

toast.success("Success message");
toast.error("Error message");
toast.info("Info message");
toast.warning("Warning message");
toast.loading("Loading message");

'top','right' | 'bottom' | 'left'

Sonner 参数

|-----------------|--------------|----------------------|-----------|-----------------------------------------------------------------|
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
| position | 位置 | string | top-right | top-left','top-right','bottom-left','bottom-right','top-center' |
| duration | 持续时间 | number | 4000 | |
| theme | 主题 | string | 'ligth | 'light,dark,system' |
| offset | 偏移量 | string,number,object | 32px | |
| mobileOffset | 移动端偏移量 | string,number,object | 16px | |
| expanded | 是否展开 | boolean | false | true,false |
| richColors | 是否显示彩色 | boolean | false | true,false |
| visibleToasts | 显示的 toast 数量 | number | 3 | |
| closeButton | 是否显示关闭按钮 | boolean | false | true,false |
| direction | 方向 | string | 'ltr' | 'ltr','rtl' |
| swipeDirections | 滑动方向 | string | 'up' | 'up','down' |
| hotkeys | 快捷键 | boolean | false | true,false |
| invert | 是否反转 | boolean | false | true,false |
| toastOptions | toast 选项 | object | {} | |
| gap | 间距 | number | 16px | |
| icons | 自定义图标 | object | object | |

Sonner 示例

toastOptions 设置

复制代码
import { Toaster } from "sonner";

function App() {
  return (
    <div className="App">
      <Toaster
        toastOptions={{
          style: {
            background: "red",
          },
          className: "my-toast",
          classNames: {
            toast: "my-toast",
            icon: "my-icon",
            message: "my-message",
          },
          descriptionClassName: "my-description",
          cancelButtonStyle: React.CSSProperties,
          actionButtonStyle: React.CSSProperties,
        }}
      />
    </div>
  );
}

export default App;

更多参数配置,请往下参考 toast 方法参数

icons 自定义

复制代码
import { Toaster } from "sonner";

function App() {
  return (
    <div className="App">
      <Toaster
        icons={{
          success: <CheckCircle />,
          error: <XCircle />,
          warning: <ExclamationCircle />,
          info: <InfoCircle />,
          loading: <Spinner />,
        }}
      />
    </div>
  );
}

export default App;

toast 参数

|--------------------|------------|-----------|---------|------------|-----------------------------------------------------------------|
| 参数 | 说明 | 类型 | 默认值 | 可选值 | |
| description | 描述 | string | | | |
| icon | 图标 | ReactNode | | | |
| duration | 持续时间 | number | 4000 | | |
| position | 位置 | string | | top-right | top-left','top-right','bottom-left','bottom-right','top-center' |
| closeButton | 是否显示关闭按钮 | boolean | false | true,false | |
| invert | 是否反转 | boolean | false | true,false | |
| dismissible | 是否可手动关闭 | boolean | true | true,false | |
| action | 确认按钮 | ReactNode | | | |
| cancelButton | 取消按钮 | ReactNode | | | |
| id | 唯一标识 | number | string | | |
| onDismiss | 关闭回调函数 | function | ()=>{} | | |
| onAutoClass | 超时自动关闭回调函数 | function | ()=>{} | | |
| containerAriaLabel | 容器 aria 标签 | string | | | |
| actionButtonStyle | 确认按钮样式 | object | | | |
| cancelButtonStyle | 取消按钮样式 | object | | | |

toast 示例

更新 toast

复制代码
import { toast } from "sonner";

function Demo() {
  const updateToast = () => {
    const toastId = toast("Sonner");
    setTimeout(() => {
      toast("updateed toast", {
        id: toastId,
      });
    }, 3000);
  };

  return (
    <div className="demo">
      <button onClick={updateToast}>Update Toast</button>
    </div>
  );
}

export default App;

自定义 Toast 关闭倒计时显示

useCountdown.js

复制代码
import { useState, useEffect, useCallback } from "react";

/**
 * 倒计时 Hook
 * @param initialSeconds 初始倒计时秒数
 * @param onEnd 倒计时结束回调
 * @returns [剩余秒数, 重启倒计时函数]
 */
export function useCountdown(initialSeconds, onEnd) {
  const [seconds, setSeconds] = useState(initialSeconds);

  // 重启倒计时
  const restart = useCallback(
    (newSeconds) => {
      // 允许动态修改初始时间,默认使用原始初始值
      setSeconds(newSeconds ?? initialSeconds);
    },
    [initialSeconds]
  );

  useEffect(() => {
    if (seconds <= 0) {
      onEnd?.();
      return;
    }

    const timer = setInterval(() => {
      setSeconds((prev) => {
        if (prev <= 1) {
          clearInterval(timer);
          onEnd?.();
          return 0;
        }
        return prev - 1;
      });
    }, 1000);

    return () => clearInterval(timer);
  }, [seconds, onEnd]);

  return [seconds, restart];
}

EasySonner.jsx

复制代码
import { toast } from "sonner";
import { useCountdown } from "useCountdown";

export default function EasySonner({
  initialSeconds = 4,
  message,
  isCountdown = true,
  isClose = true,
}) {
  const [seconds] = useCountdown(initialSeconds, () => {
    toast.dismiss();
  });

  return (
    <div className="flex w-full items-center justify-between">
      <div className="flex-1 items-center flex gap-2">
        {isClose && (
          <i
            className="inline-block h-[max-content] w-[max-content] sysicon sysicon-alert-error text-field-error text-[14px]"
            onClick={() => {
              toast.dismiss();
            }}
          ></i>
        )}
        {message}
      </div>
      {isCountdown && <div>{seconds}s</div>}
    </div>
  );
}

使用

复制代码
import { toast } from "sonner";
import EasySonner from "EasySonner";

const duration = 10; // 10秒
const promise = new Promise((resolve) => {
  setTimeout(resolve, 1000 * duration); // 模拟异步操作
});

toast.promise(promise, {
  duration: 1000 * duration,
  icon: null, // 不显示loading图标
  loading: (
    <EasySonner
      initialSeconds={duration}
      message="Please agree"
      isCountdown={true}
      isClose={true}
    />
  ),
});

参数

|----------------|----------|---------|------|
| 参数 | 说明 | 类型 | 默认值 |
| initialSeconds | 初始秒数 | number | 4 |
| message | 提示内容 | string | -- |
| isCountdown | 是否倒计时 | boolean | true |
| isClose | 是否显示关闭按钮 | boolean | true |

预览地址

相关推荐
秋田君9 分钟前
深入理解JavaScript设计模式之命令模式
javascript·设计模式·命令模式
中微子39 分钟前
React 状态管理 源码深度解析
前端·react.js
风吹落叶花飘荡2 小时前
2025 Next.js项目提前编译并在服务器
服务器·开发语言·javascript
加减法原则2 小时前
Vue3 组合式函数:让你的代码复用如丝般顺滑
前端·vue.js
yanlele2 小时前
我用爬虫抓取了 25 年 6 月掘金热门面试文章
前端·javascript·面试
lichenyang4532 小时前
React移动端开发项目优化
前端·react.js·前端框架
天若有情6732 小时前
React、Vue、Angular的性能优化与源码解析概述
vue.js·react.js·angular.js
你的人类朋友2 小时前
🍃Kubernetes(k8s)核心概念一览
前端·后端·自动化运维
web_Hsir2 小时前
vue3.2 前端动态分页算法
前端·算法
烛阴3 小时前
WebSocket实时通信入门到实践
前端·javascript