How to fix "TypeError: Object(...) is not a function" when using a wrap function on React Component to authenticate user login with Browser Router

How to fix "TypeError: Object(...) is not a function" when using a wrap function on React Component to authenticate user login with Browser Router

我正在构建一个 React 应用程序并处理它的用户身份验证。 目前我正在使用 'react-router-dom' 的 BrowserRouter 来管理我的应用程序中的路由。 我有一个注册路线,所有其他路线组件都包装在一个函数 'withAuth' 中。 'withAuth' 的作用是查看应用程序是否已通过身份验证。如果用户已通过身份验证,则应加载该组件(此处有问题!),否则应将其重定向到登录组件(工作正常!)。

登录后,当应用程序重定向到组件包含在 'withAuth' 函数中的路径时。我收到以下错误:

TypeError: Object(...) is not a function (anonymous function) F:/Projects/beyouplus/beyouplus/beyouplus-client/src/services/auth.service.js:14

11 | return useContext(MyContext)

12 | }

13 |

>14 | export const withAuth = (Component) => (props) => {

15 | if (!isSignedIn()) {

16 | if (props.history.location.pathname === '/sign-in') {

17 | return null

我的App.js:

import React from 'react';
import {
  BrowserRouter,
  Route,
  Redirect
} from 'react-router-dom'

// Import Screens
import SignInScreen from './components/SignInScreen'
import DepartmentScreen from './components/DepartmentScreen'

// Import Services
import { withAuth } from './services/auth.service'

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

const redirectToDept = () => (
  <Redirect to="/dept" />
)

export default App;

auth.service.js 文件:

import React, { useContext } from 'react'
import { Redirect } from 'react-router-dom'

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) => {
    if (!isSignedIn()) {
        if (props.history.location.pathname === '/sign-in') {
            return null
        }

        return (
            <Redirect to="/sign-in" />
        )
    }

    const { data, error, loading } = getMeQuery()

    useCacheService()

    if(loading) return null

    if(error || !data.me) {
        signOut()

        return <Redirect to="/sign-in" />
    }

    console.log(data.me)

    return (
        <MyContext.Provider value={data.me}>
            <Component {...props} />
        </MyContext.Provider>
    )
}

export const isSignedIn = () => {
    //return /authToken=.+(;!$)/.test(document.cookie)
    return document.cookie.includes('authToken')
}

编辑: 我发现问题出在用 Auth HOC 声明它的语法上,我用以下内容更新了它,它加载得很好。 除了现在我使用 "componentDidMount" 进行 graphql 查询时, HOC 不是 运行 "componentDidMount"。 auth.service.js

export const withAuth = (Component) => {
    return class extends React.Component {

        state = {
            data: null
        }

        componentDidMount() {
            if (!isSignedIn()) {
                if (this.props.history.location.pathname === '/sign-in') {
                    return null;
                }
                return (
                    <Redirect to="/sign-in" />
                );
            }

            const { data, error, loading } = getMeQuery;

            useCacheService();

            if (loading) return null;
            if (data === undefined) return null;

            if (error || !data.me) {
                signOut();
                return <Redirect to="/sign-in" />;
            }

            this.setState({
                data
            })
        }

        render() {       
            const { data } = this.state;

            return (
                <MyContext.Provider value={data.me}>
                    <Component {...this.props} />
                </MyContext.Provider>
            )
        }
    }
}

所以我得到了错误

TypeError: Cannot read property 'me' of null

/> 52 | < MyContext.Provider value={data.me} >

来自 HOC 中的 render()。

所以在搜索了几个小时之后,我终于找到了解决上述问题的方法。

回顾一下,我使用 react-router-dom 来处理我的应用程序中从登录组件到我的仪表板的路由。我向所有其他路由组件添加了一个 HOC,期望 SignIn 组件检查用户是否已通过身份验证;如果不是,则用户被路由回登录组件。

问题如下:

  1. 我收到一个 TypeError: Object(...) is not a function,在我的 HOC 中验证 logged-in 用户。
  2. 在 HOC 中,我无法进行 graphql 查询并获取当前用户的 data.me。

解决方法:

  • HOC 类型错误:我的语法错误,我没有返回组件!

A higher-order component is a function that takes a component and returns a new component.

  • 得到data.me:

    1. 要使用 apollo 进行 graphql 查询,需要访问 client.

    2. 我必须确保从 'ApolloProvider' 到 'react-apollo' 从根目录传递客户端。

    3. 比使用来自 'react-apollo' 的查询来查询 graphql 服务器,并处理数据、错误和加载。

这是我的新 auth.service!

export const withAuth = (Component) => {
    return class extends React.Component {
        render() {
            if (!isSignedIn()) {
                if (this.props.history.location.pathname === '/sign-in') {
                    return null;
                }
                return (
                    <Redirect to="/sign-in" />
                );
            }

            useCacheService();

            return (
                <Query query={getMeQuery}>
                    {({ loading, error, data }) => {
                        if (loading) {
                            return (
                                <div>
                                    Loading
                                </div>
                            );
                        }

                        if (error || !data.me) {
                            signOut();
                            console.log(error)
                            return (
                                <Redirect to="/sign-in" />
                            );
                        }

                        return (
                            <MyContext.Provider value={data.me}>
                                <Component {...this.props} />
                            </MyContext.Provider>
                        )
                    }}
                </Query>
            )
        }
    }
}