fix(NotificationContainer): 修复 React Hooks 调用顺序错误
**问题描述**
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 <noreply@anthropic.com>
This commit is contained in:
@@ -346,6 +346,11 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
|
|||||||
`${typeConfig.colorScheme}.200`,
|
`${typeConfig.colorScheme}.200`,
|
||||||
`${typeConfig.colorScheme}.700`
|
`${typeConfig.colorScheme}.700`
|
||||||
);
|
);
|
||||||
|
// 最新通知的 borderTopColor(避免在条件语句中调用 Hook)
|
||||||
|
const newestBorderTopColor = useColorModeValue(
|
||||||
|
`${typeConfig.colorScheme}.100`,
|
||||||
|
`${typeConfig.colorScheme}.700`
|
||||||
|
);
|
||||||
|
|
||||||
// 使用 useMemo 缓存颜色对象(避免不必要的重新创建)
|
// 使用 useMemo 缓存颜色对象(避免不必要的重新创建)
|
||||||
const colors = useMemo(() => ({
|
const colors = useMemo(() => ({
|
||||||
@@ -357,7 +362,8 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
|
|||||||
metaText: metaTextColor,
|
metaText: metaTextColor,
|
||||||
hoverBg: hoverBgColor,
|
hoverBg: hoverBgColor,
|
||||||
closeButtonHoverBg: closeButtonHoverBgColor,
|
closeButtonHoverBg: closeButtonHoverBgColor,
|
||||||
}), [priorityBgColor, borderColor, iconColor, textColor, subTextColor, metaTextColor, hoverBgColor, closeButtonHoverBgColor]);
|
newestBorderTop: newestBorderTopColor,
|
||||||
|
}), [priorityBgColor, borderColor, iconColor, textColor, subTextColor, metaTextColor, hoverBgColor, closeButtonHoverBgColor, newestBorderTopColor]);
|
||||||
|
|
||||||
// 点击处理(只有真正可点击时才执行)- 使用 useCallback 优化
|
// 点击处理(只有真正可点击时才执行)- 使用 useCallback 优化
|
||||||
const handleClick = useCallback(() => {
|
const handleClick = useCallback(() => {
|
||||||
@@ -430,7 +436,7 @@ const NotificationItem = React.memo(({ notification, onClose, isNewest = false }
|
|||||||
borderRight: '1px solid',
|
borderRight: '1px solid',
|
||||||
borderRightColor: colors.border,
|
borderRightColor: colors.border,
|
||||||
borderTop: '1px solid',
|
borderTop: '1px solid',
|
||||||
borderTopColor: useColorModeValue(`${typeConfig.colorScheme}.100`, `${typeConfig.colorScheme}.700`),
|
borderTopColor: colors.newestBorderTop,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{/* 头部区域:标题 + 可选标识 */}
|
{/* 头部区域:标题 + 可选标识 */}
|
||||||
|
|||||||
Reference in New Issue
Block a user