【问题标题】:React Invalid hook call. Hooks can only be called inside of the body of a function component反应无效的钩子调用。 Hooks 只能在函数组件的主体内部调用
【发布时间】:2020-12-06 19:42:51
【问题描述】:

我是新手,目前正在尝试解决此错误。基本上我正在创建一个基于 axios 的 HttpAuthClient 并希望为每个请求添加访问令牌。当我尝试单击按钮时,我收到一个错误 - “未处理的拒绝(错误):无效的钩子调用。钩子只能是在函数组件的主体内部调用”。

组件

import React, { useState } from 'react';
import { HttpAuthClient } from "../HttpAuthClient/HttpAuthClient";

export const Content = () => {

    const [pages, setPages] = useState(null);
    const apiUrl = "https://xxxxx/";
           
    const loadPages = async () => {
        const response = await HttpAuthClient.get(apiUrl); //Error thrown
        setPages(response.data);
        console.log(pages);

    };
    
    return (
        <button onClick={loadPages}>Load Pages</button>
    )
};

HttpAuthClient

import Axios, { AxiosRequestConfig } from 'axios';
import { useAuthContext } from '../AuthContext/AuthContext';

const RequestHandler = (request: AxiosRequestConfig) => {
    const { accessToken, isAuthenticated } = useAuthContext(); //Error thrown

    if (isAuthenticated) {
        request.headers['Authorization'] = `Bearer ${accessToken}`;
    }

    return request;
};

const HttpAuthClient = Axios.create();

HttpAuthClient.interceptors.request.use((request: AxiosRequestConfig) =>
    RequestHandler(request)
);

export default HttpAuthClient;

AuthContext

import { createContext, useContext } from 'react';
import { IAuthContext } from '../../types/IAuthContext';

export const AuthContext = createContext<IAuthContext>({
    user: null,
    isAuthenticated: null,
    accessToken: ''
});

export const useAuthContext = () => useContext(AuthContext);

身份验证提供者

import React, { useState, useEffect } from 'react';
import { useOktaAuth } from '@okta/okta-react';
import { AuthContext } from '../../components/AuthContext/AuthContext';
import { IAuthContext } from '../../types/IAuthContext';
import { IUserInfo } from '../../types/IUserInfo';

const AuthProvider = (props: any) => {
    const { authState, authService } = useOktaAuth();
    const [authContext, setAuthContext] = useState<IAuthContext>(
        {} as IAuthContext
    );

    useEffect(() => {
        if (!authState.isAuthenticated) {
            setAuthContext({} as IAuthContext);
        } else {
            authService.getUser().then((info: IUserInfo) => {
                setAuthContext({
                    accessToken: authState.accessToken,
                    isAuthenticated: authState.isAuthenticated,
                    user: info
                });
            });
        }
    }, [authState, authService]);

    return (
        <AuthContext.Provider value={authContext}>
            {props.children}
        </AuthContext.Provider>
    );
};

export default AuthProvider;

反应堆栈跟踪

react-dom.development.js:14724 Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
    at Object.throwInvalidHookError (react-dom.development.js:14724)
    at useContext (react.development.js:1493)
    at useAuthContext (AuthContext.tsx:10)
    at RequestHandler (HttpAuthClient.tsx:5)
    at HttpAuthClient.tsx:16
    at async loadPages (Content.tsx:10)

【问题讨论】:

  • 如果您 export default HttpAuthClient,则您的 HttpAuthClient 导入不正确。
  • 你也可以分享堆栈跟踪吗?
  • @tmhao2005 - 查看堆栈跟踪更新。
  • 这个错误听起来很直接。您正在 http 拦截器中尝试使用钩子 useContext :) 您只应该在组件的主体中调用它
  • 是否可以通过 AuthProvider 向 http 拦截器添加令牌?我指的是shooksweb.com/react-okta-axios-interceptor,但不确定我是否可以在功能组件中做到这一点。任何代码 sn-p 都会有帮助吗?

标签: reactjs axios


【解决方案1】:

正如错误所说

"Unhandled Rejection (Error): Invalid hook call. Hooks can only be called inside of the body of a function component"

您不能在组件之外使用钩子,并且您的 RequestHandler 不是组件, 你需要找到另一种方式来给它你的令牌,比如 redux 商店。

您也可以使用 cookie 或本地存储/会话存储等网络存储,但这可能是安全漏洞Is it safe to store a jwt in localStorage with reactjs?

【讨论】:

  • 嗨 Damien,是否可以避免使用 redux store。我正在考虑的另一种选择是使用本地存储并获取访问令牌,因为 okta 保存在其中。
  • 是的,本地存储是一个不错的选择,您也可以保持令牌槽刷新,但您需要注意安全隐患,尤其是 XSS stackoverflow.com/questions/44133536/…
猜你喜欢
  • 2020-01-18
  • 2021-03-12
  • 2021-02-08
  • 2020-06-22
  • 2019-09-07
  • 2021-10-18
  • 1970-01-01
  • 1970-01-01
  • 2022-06-15
相关资源
最近更新 更多