Как исправить «TypeError: Object (...) не является функцией» при использовании функции обтекания в React Component для аутентификации входа пользователя с помощью Browser Router - PullRequest
0 голосов
/ 09 июня 2019

Я создаю приложение React и работаю над его аутентификацией пользователя. В настоящее время я использую BrowserRouter из реагирующего маршрутизатора для управления маршрутизацией в моем приложении. У меня есть регистрация Route и все другие компоненты Routes обернуты в функцию «withAuth». Роль 'withAuth' состоит в том, чтобы видеть, имеет ли приложение аутентифицированное использование. Если пользователь прошел аутентификацию, компонент должен загрузиться (проблема здесь!), Иначе он должен быть перенаправлен на компонент входа (работает нормально!).

После входа в систему, когда приложение перенаправляет на путь, по которому компонент помещается в функцию withAuth. Я получаю следующую ошибку:

TypeError: Object (...) не является функцией (анонимная функция) F: /Projects/beyouplus/beyouplus/beyouplus-client/src/services/auth.service.js: 14

11 | return useContext (MyContext)

12 | } * +1010 *

13 |

> 14 | экспорт const withAuth = (Компонент) => (реквизит) => {

15 | if (! isSignedIn ()) {

16 | if (props.history.location.pathname === '/ вход в систему') {

17 | вернуть ноль

My 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')
}

EDIT: Я пришел, чтобы выяснить, что проблема была с синтаксисом объявления этого с помощью AOC 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: Невозможно прочитать свойство 'me' со значением NULL

/> 52 |

из render () внутри HOC.

1 Ответ

0 голосов
/ 10 июня 2019

Итак, после поиска часов, я наконец смог найти решение для своей проблемы выше.

Напомню, что я использовал response-router-dom для управления маршрутизацией в моем приложении от компонента SignIn до My Dashboard. Я добавил HOC ко всем другим компонентам маршрутов, ожидая, что компонент SignIn проверит, аутентифицирован ли пользователь; если не пользователь был перенаправлен обратно в компонент входа.

Проблемы были следующими:

  1. Я получил сообщение об ошибке TypeError: Object (...) не является функцией внутри моего HOC для проверки вошедшего в систему пользователя.
  2. Когда я находился в HOC, мне не удалось выполнить запрос к graphql и получить data.me текущего пользователя.

Решение:

  • Ошибка HOC TypeEr: мой синтаксис был неправильным, я не возвращал компонент!

Компонент высшего порядка - это функция, которая принимает компонент и возвращает новый компонент.

  • Для получения data.me:

    1. Чтобы сделать запрос graphql с использованием apollo, необходимо иметь доступ к client .

    2. Мне нужно было убедиться, что я передавал клиента из «ApolloProvider» через «response-apollo» из корня.

    3. Чем использовать Query из'act-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>
            )
        }
    }
}
...