Files
vf_react/src/hooks/useAuthModal.js
zdl d5881462d2 feat: 将 AuthModalProvider 迁移到 Redux
## 主要改动

### 新增
- 创建 `store/slices/authModalSlice.js` - Redux Slice 管理认证弹窗状态
- 创建 `hooks/useAuthModal.js` - 自定义 Hook,组合 Redux 状态和业务逻辑

### 修改
- 更新 `store/index.js` - 添加 authModal reducer
- 更新 `App.js` - 移除 AuthModalProvider 包裹层
- 更新 5 个组件的 import 路径:
  - AuthFormContent.js
  - AuthModalManager.js
  - WechatRegister.js
  - HomeNavbar.js
  - ProtectedRoute.js

### 删除
- 删除 `contexts/AuthModalContext.js` - 旧的 Context 实现

## 迁移效果

-  减少 Provider 嵌套层级(4层 → 3层)
-  统一状态管理架构(Redux)
-  更好的调试体验(Redux DevTools)
-  保持 API 兼容性(无破坏性修改)

## 技术细节

- 使用 `useRef` 存储 `onSuccessCallback`(函数不可序列化)
- 保持与 AuthContext 的依赖关系(AuthProvider 暂未迁移)
- 所有业务逻辑保持不变,仅改变状态管理方式

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 13:22:45 +08:00

117 lines
3.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// src/hooks/useAuthModal.js
// 认证弹窗自定义 Hook - 组合 Redux 状态和业务逻辑
import { useCallback, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import {
openModal,
closeModal,
selectAuthModalOpen,
selectRedirectUrl
} from '../store/slices/authModalSlice';
import { useAuth } from '../contexts/AuthContext';
import { logger } from '../utils/logger';
/**
* 认证弹窗自定义 Hook
*
* 功能:
* - 管理认证弹窗的开关状态
* - 处理登录成功后的回调和跳转
* - 未登录时关闭弹窗自动跳转到首页
*
* 注意:
* - onSuccessCallback 使用 ref 存储(函数不可序列化,不能放 Redux
* - 依赖 AuthContext 读取 isAuthenticatedAuthProvider 暂未迁移)
*
* @returns {object} 弹窗状态和操作方法
*/
export const useAuthModal = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
// Redux 状态
const isAuthModalOpen = useSelector(selectAuthModalOpen);
const redirectUrl = useSelector(selectRedirectUrl);
// AuthContext 状态(暂未迁移到 Redux
const { isAuthenticated } = useAuth();
// 使用 ref 存储回调函数(不能放 Redux因为函数不可序列化
const onSuccessCallbackRef = useRef(null);
/**
* 打开认证弹窗(统一的登录/注册入口)
* @param {string} url - 认证成功后的重定向URL可选
* @param {function} callback - 认证成功后的回调函数(可选)
*/
const openAuthModal = useCallback((url = null, callback = null) => {
onSuccessCallbackRef.current = callback;
dispatch(openModal({ redirectUrl: url }));
logger.debug('useAuthModal', '打开认证弹窗', {
redirectUrl: url || '无',
hasCallback: !!callback
});
}, [dispatch]);
/**
* 关闭认证弹窗
* 如果用户未登录,跳转到首页
*/
const closeAuthModal = useCallback(() => {
dispatch(closeModal());
onSuccessCallbackRef.current = null;
// ⭐ 如果用户关闭弹窗时仍未登录,跳转到首页
if (!isAuthenticated) {
navigate('/home');
logger.debug('useAuthModal', '未登录关闭弹窗,跳转到首页');
} else {
logger.debug('useAuthModal', '关闭认证弹窗');
}
}, [dispatch, isAuthenticated, navigate]);
/**
* 登录/注册成功处理
* @param {object} user - 用户信息
*/
const handleLoginSuccess = useCallback((user) => {
// 执行自定义回调(如果有)
if (onSuccessCallbackRef.current) {
try {
onSuccessCallbackRef.current(user);
logger.debug('useAuthModal', '执行成功回调', {
userId: user?.id
});
} catch (error) {
logger.error('useAuthModal', 'handleLoginSuccess 回调执行失败', error, {
userId: user?.id,
hasCallback: !!onSuccessCallbackRef.current
});
}
}
// ⭐ 登录成功后,只关闭弹窗,留在当前页面(不跳转)
// 移除了原有的 redirectUrl 跳转逻辑
dispatch(closeModal());
onSuccessCallbackRef.current = null;
logger.debug('useAuthModal', '登录成功,关闭弹窗', {
userId: user?.id
});
}, [dispatch]);
return {
// 状态
isAuthModalOpen,
redirectUrl,
// 方法
openAuthModal,
closeModal: closeAuthModal,
handleLoginSuccess,
};
};