From 0364b3a9273d039c662f831502b15a2367ee0be4 Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Thu, 30 Oct 2025 18:43:19 +0800 Subject: [PATCH] =?UTF-8?q?fix(NotificationContainer):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20React=20Hooks=20=E8=B0=83=E7=94=A8=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **问题描述** React 检测到 NotificationItem 组件中 Hooks 调用顺序不一致: ``` Warning: React has detected a change in the order of Hooks called by null. Previous render: 24. useCallback Next render: 25. useContext ``` **根本原因** 在第 433 行,`useColorModeValue` Hook 在条件对象展开中被调用: ```javascript {...(isNewest && { borderTopColor: useColorModeValue(...), // ❌ 违反 Hooks 规则 })} ``` 当 `isNewest` 值变化时: - `isNewest = false` → Hook 不调用 - `isNewest = true` → Hook 调用 - 导致不同渲染的 Hooks 数量不一致 **React Hooks 规则** > Hooks 必须在组件顶层调用,不能在条件语句、循环或嵌套函数中调用 **修复内容** 1. **将 Hook 移到组件顶层** (第 349-353 行) ```javascript // 最新通知的 borderTopColor(避免在条件语句中调用 Hook) const newestBorderTopColor = useColorModeValue( `${typeConfig.colorScheme}.100`, `${typeConfig.colorScheme}.700` ); ``` 2. **添加到 colors 对象** (第 365 行) ```javascript const colors = useMemo(() => ({ // ... 其他颜色 newestBorderTop: newestBorderTopColor, }), [/* dependencies */]); ``` 3. **在 JSX 中使用预计算的值** (第 439 行) ```diff {...(isNewest && { - borderTopColor: useColorModeValue(...), + borderTopColor: colors.newestBorderTop, })} ``` **修复验证** - ✅ 所有 Hooks 在每次渲染都以相同顺序调用 - ✅ 消除 React Hooks 警告 - ✅ 功能保持不变(视觉效果一致) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/components/NotificationContainer/index.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/NotificationContainer/index.js b/src/components/NotificationContainer/index.js index 5deca5c5..4bb338d4 100644 --- a/src/components/NotificationContainer/index.js +++ b/src/components/NotificationContainer/index.js @@ -346,6 +346,11 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false } `${typeConfig.colorScheme}.200`, `${typeConfig.colorScheme}.700` ); + // 最新通知的 borderTopColor(避免在条件语句中调用 Hook) + const newestBorderTopColor = useColorModeValue( + `${typeConfig.colorScheme}.100`, + `${typeConfig.colorScheme}.700` + ); // 使用 useMemo 缓存颜色对象(避免不必要的重新创建) const colors = useMemo(() => ({ @@ -357,7 +362,8 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false } metaText: metaTextColor, hoverBg: hoverBgColor, closeButtonHoverBg: closeButtonHoverBgColor, - }), [priorityBgColor, borderColor, iconColor, textColor, subTextColor, metaTextColor, hoverBgColor, closeButtonHoverBgColor]); + newestBorderTop: newestBorderTopColor, + }), [priorityBgColor, borderColor, iconColor, textColor, subTextColor, metaTextColor, hoverBgColor, closeButtonHoverBgColor, newestBorderTopColor]); // 点击处理(只有真正可点击时才执行)- 使用 useCallback 优化 const handleClick = useCallback(() => { @@ -430,7 +436,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false } borderRight: '1px solid', borderRightColor: colors.border, borderTop: '1px solid', - borderTopColor: useColorModeValue(`${typeConfig.colorScheme}.100`, `${typeConfig.colorScheme}.700`), + borderTopColor: colors.newestBorderTop, })} > {/* 头部区域:标题 + 可选标识 */}