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

React中withAuth高阶组件结合Browser Router的类型错误及后续问题

解决React withAuth高阶组件的路由验证与GraphQL查询问题

看起来你在React身份验证的高阶组件(HOC)上遇到了两个关键问题:函数式HOC的调用错误,以及类组件HOC中无法使用Hooks导致的查询失败。让我们一步步拆解并解决这些问题:

一、原函数式HOC的错误原因分析

你最初遇到的TypeError: Object(...) is not a function报错,核心原因是错误调用了GraphQL查询:

  • getMeQuery应该是一个GraphQL查询文档(字符串或gql解析后的对象),而非可直接执行的函数。你需要用对应的React Hooks(比如Apollo Client的useQuery)来执行它,而不是直接写getMeQuery()。
  • 另外,虽然函数式HOC的结构本身合规,但路由重定向的逻辑可以更严谨。

二、修正后的函数式withAuth HOC(推荐方案)

函数式HOC结合React Hooks是更现代、简洁的写法,我们调整查询方式并优化验证逻辑:

import React, { useContext } from 'react'
import { Redirect } from 'react-router-dom'
import { useQuery } from '@apollo/client' // 按你的GraphQL客户端替换,比如urql的useQuery
import client from '../client'
import { getMeQuery } from '../graphql/queries'
import { useCacheService } from './cache.service'

const MyContext = React.createContext(null)

export const useMe = () => {
  return useContext(MyContext)
}

export const withAuth = (Component) => (props) => {
  // 第一步:检查cookie中的登录状态
  const isLoggedIn = isSignedIn()

  // 未登录时直接重定向到登录页,避免循环重定向
  if (!isLoggedIn) {
    if (props.history.location.pathname === '/sign-in') {
      return null
    }
    return <Redirect to="/sign-in" />
  }

  // 第二步:用useQuery执行GraphQL用户信息查询(关键修正)
  const { data, error, loading } = useQuery(getMeQuery)
  // 自定义钩子仅能在函数组件/自定义钩子中使用,此处合法
  useCacheService()

  // 查询加载中:返回加载提示或骨架屏
  if (loading) return <div>正在验证身份...</div>

  // 查询出错或无用户数据:登出并跳回登录页
  if (error || !data?.me) {
    signOut()
    return <Redirect to="/sign-in" />
  }

  // 验证通过:传递用户上下文并渲染目标组件
  return (
    <MyContext.Provider value={data.me}>
      <Component {...props} />
    </MyContext.Provider>
  )
}

export const isSignedIn = () => {
  return document.cookie.includes('authToken')
}

// 补充登出逻辑(确保清除登录状态)
export const signOut = () => {
  document.cookie = 'authToken=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;'
}

三、类组件HOC的问题说明

你改成类组件后遇到的componentDidMount未执行、data.me为null的问题,根源在于:

  1. 类组件禁止使用React Hooks:useCacheService和useQuery都是Hooks,只能在函数组件或自定义钩子中使用,类组件中调用它们会直接失效甚至触发报错。
  2. 生命周期方法不能返回JSX:componentDidMount仅能执行逻辑操作,不能返回组件,你在其中写的return <Redirect />完全不会生效,重定向逻辑必须移到render方法中处理。

如果一定要用类组件实现,你需要通过GraphQL客户端的直接查询方法(比如Apollo的client.query)获取数据,但这种写法远不如函数式HOC简洁,因此更推荐上面的函数式方案。

四、App.js代码验证

你的App.js代码本身无问题,可补充小细节确保逻辑完整:

import React from 'react';
import { BrowserRouter, Route, Redirect } from 'react-router-dom'
import SignInScreen from './components/SignInScreen'
import DepartmentScreen from './components/DepartmentScreen'
import { withAuth } from './services/auth.service'

// 提前定义重定向函数,避免组件内部嵌套
const redirectToDept = () => (
  <Redirect to="/dept" />
)

const App = () => (
 <BrowserRouter>
   <Route exact path="/sign-in" component={SignInScreen}/>
   <Route exact path="/dept" component={withAuth(DepartmentScreen)}/>
   <Route exact path="/" render={redirectToDept} />
 </BrowserRouter>
)

export default App;

内容的提问来源于stack exchange,提问作者thisis-Shitanshu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:25:38