React 中如何在渲染映射中安全使用 Hook 返回的函数

11次阅读

React 中如何在渲染映射中安全使用 Hook 返回的函数

react 中,不能在组件外部或条件逻辑中调用 hook,因此无法将 `usefirebaseauth()` 等 hook 返回的函数(如 `signinwithapple`)直接写入全局常量数组。正确做法是将数据结构移入组件内部或封装为自定义 hook,确保 hook 调用符合规则。

react 的 Hooks 规则(尤其是「只能在顶层调用 Hook」)意味着:所有 Hook 必须在组件函数体最外层、无条件执行。你最初尝试将 signInWithapple 直接赋值给模块级常量 socialAuthMethodsmap,违反了这一规则——因为此时 useFirebaseAuth() 尚未被调用,signInWithapple 甚至不存在。

✅ 正确方案一:在组件内声明映射数据

将 socialAuthMethodsMap 定义在组件作用域中,并在 Hook 调用之后立即使用其返回值:

import { FunctionComponent, MouseEventHandler } from 'react'; import { IconProps } from 'react-feather'; import { useFirebaseAuth } from './hooks/useFirebaseAuth'; // 假设路径 import { SocialAuthButton } from './components/SocialAuthButton';  type TSocialAuthMethodData = {   code: string;   logo?: string | FunctionComponent;   onClick: MouseEventHandler; };  const MyAuthPage = () => {   const { signInWithApple } = useFirebaseAuth();    const socialAuthMethodsMap: TSocialAuthMethodData[] = [     {       code: 'apple',       logo: '/assets/icons/social/apple.svg',       onClick: signInWithApple, // ✅ 此时 signInWithApple 已有效     },     {       code: 'google',       logo: '/assets/icons/social/google.svg',       onClick: () => console.log('Google auth placeholder'),     },     {       code: 'github',       logo: '/assets/icons/social/github.svg',       onClick: () => console.log('gitHub auth placeholder'),     },   ];    return (     
{socialAuthMethodsMap.map((method) => ( ))}
); }; export default MyAuthPage;

? 提示:onClick 回调需保持稳定(避免每次渲染都新建匿名函数),此处 signInWithApple 是 Hook 返回的稳定引用,符合最佳实践。

✅ 正确方案二:封装为自定义 Hook(推荐复用场景)

当多个组件需要相同认证方法配置时,可抽象为 useSocialAuthData 自定义 Hook:

// hooks/useSocialAuthData.ts import { useFirebaseAuth } from './useFirebaseAuth'; import { TSocialAuthMethodData } from '../types';  export const useSocialAuthData = (): TSocialAuthMethodData[] => {   const { signInWithApple } = useFirebaseAuth();    return [     {       code: 'apple',       logo: '/assets/icons/social/apple.svg',       onClick: signInWithApple,     },     {       code: 'google',       logo: '/assets/icons/social/google.svg',       onClick: () => alert('Google login not implemented yet'),     },     {       code: 'github',       logo: '/assets/icons/social/github.svg',       onClick: () => alert('github login not implemented yet'),     },   ]; };

在组件中使用:

const MyAuthPage = () => {   const socialAuthMethodsMap = useSocialAuthData(); // ✅ Hook 调用合规    return (     
{socialAuthMethodsMap.map((method) => ( ))}
); };

⚠️ 注意事项

  • 禁止在 map、Filter、条件语句、普通函数内部调用 Hook;
  • ✅ 自定义 Hook 名称必须以 use 开头(如 useSocialAuthData),这是 React 识别 Hook 的约定;
  • ? 若 useFirebaseAuth 内部依赖 useEffect 或状态更新,请确保其自身也严格遵守 Hook 规则;
  • ? 对于动态图标(如 FunctionComponent),建议统一包装为 Reactnode 类型,提升灵活性。

通过以上任一方式,你既能保持代码组织清晰,又能完全遵守 React 的 Hooks 规范,让认证按钮逻辑安全、可维护、可复用。

text=ZqhQzanResources