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

React组件外调用useSnackbarRef值丢失问题及修复咨询

React 中 useSnackbarRef 变为 undefined 的原因及修复方案

问题根源:React 18 的关键变化

  1. Strict Mode 的双重挂载机制:React 18 在开发环境下会对组件执行两次挂载(挂载→卸载→再次挂载),用来检测未清理的副作用。原代码中,第一次挂载时useSnackbarRef被赋值,模拟卸载阶段useSnackbar返回的实例会被清理,第二次挂载时可能因 notistack 内部逻辑或全局变量未正确重新赋值,导致最终useSnackbarRef变为undefined。
  2. 并发渲染下的全局变量风险:直接将钩子返回值赋值给全局变量的方式,脱离了 React 的状态管理体系。在并发渲染机制中,组件生命周期的变化会导致钩子实例失效,全局变量无法同步这些变化,进而出现引用丢失的问题。

修复方案

方案一:优化全局变量赋值逻辑

通过useEffect和useRef控制赋值时机,避免 Strict Mode 的干扰,同时增加安全判断:

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

let snackbarRef;
export const SnackbarUtilsConfigurator = () => {
    const snackbar = useSnackbar();
    const isFirstMount = useRef(false);

    useEffect(() => {
        // 仅在第一次挂载时赋值,避免Strict Mode重复挂载覆盖
        if (!isFirstMount.current) {
            snackbarRef = snackbar;
            isFirstMount.current = true;
        }
    }, [snackbar]);

    return null;
};

const handler = {
    success(msg) {
        this.toast(msg, { variant: 'success' });
    },
    warning(msg) {
        this.toast(msg, { variant: 'warning' });
    },
    info(msg) {
        this.toast(msg, { variant: 'info' });
    },
    error(msg) {
        this.toast(msg, { variant: 'error' });
    },
    toast(msg, { variant = 'default', ...restProps }) {
        // 增加安全判断,防止引用失效时报错
        if (!snackbarRef?.enqueueSnackbar) return;
        snackbarRef.enqueueSnackbar(msg, { variant, autoHideDuration: 2000, ...restProps });
    },
};

export default handler;

方案二:使用 React Ref 对象存储(更符合 React 规范)

用 React 的createRef替代普通全局变量,进一步提升可靠性:

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

export const snackbarRef = createRef();
export const SnackbarUtilsConfigurator = () => {
    const snackbar = useSnackbar();

    useEffect(() => {
        snackbarRef.current = snackbar;
    }, [snackbar]);

    return null;
};

const handler = {
    success(msg) {
        this.toast(msg, { variant: 'success' });
    },
    warning(msg) {
        this.toast(msg, { variant: 'warning' });
    },
    info(msg) {
        this.toast(msg, { variant: 'info' });
    },
    error(msg) {
        this.toast(msg, { variant: 'error' });
    },
    toast(msg, { variant = 'default', ...restProps }) {
        if (!snackbarRef.current?.enqueueSnackbar) return;
        snackbarRef.current.enqueueSnackbar(msg, { variant, autoHideDuration: 2000, ...restProps });
    },
};

export default handler;

关键修复点

  • 用useEffect确保钩子实例仅在组件稳定挂载后赋值,规避 Strict Mode 的双重挂载干扰。
  • 添加可选链判断(?.),防止在引用未初始化或失效时触发报错。
  • 优先使用 React 原生的ref对象存储钩子实例,而非普通全局变量,更适配 React 的生命周期管理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 10:55:11