[未处理的承诺拒绝:错误:钩子调用无效。钩子只能在函数组件内部调用

时间:2021-04-02 20:20:37

标签: javascript reactjs react-native react-hooks

你好,我正在制作一个本机应用程序。这是我的第一个 react-native 项目和第二个使用 react 的项目。无论如何,我在我的本机项目中遇到了这个错误。我正在发布我的模块,请帮助我。

这是我的模块,它将个人资料图片上传到我的快递服务器。

const updateProfilePicture = image => {
    try {
        console.log("Update profile picture hit");
        const { user: token } = useAuth();
        console.log(`Token received: ${token}`);
        const data = new FormData();

        console.log(image);
        
        let fileName = image.split("/");
        fileName = fileName[fileName.length-1]
        console.log(`File name: ${fileName}`)
        let extensionName = fileName.split(".");
        extensionName = extensionName[extensionName.length-1];
        console.log(`Extension name: ${extensionName}`)

        data.append('token', token);

        data.append('pimage', {
            name: Random.getRandomBytes(8).toString('hex')+"."+extensionName,
            type: 'image/'+extensionName,
            uri: image
        });

        console.log(`This is the data\n`+data);

        return authClient.post(endpointUpdatePicture, data);
    } catch(error) {
        console.log("Error in update profile picture", error);
    }
};

通过点击和尝试,我发现 const { user: token } = useAuth(); 行出错了。

在继续之前,useAuth() 是我用于跟踪用户的自定义钩子。 user 实际上是一个 jwt 令牌。

这是我的 useAuth()

import { useContext } from 'react';

import authStorage from './storage';
import AuthContext from './context';

import jwt from 'jwt-decode';

export default useAuth = () => {

    const {user, setUser} = useContext(AuthContext);

    const { name, rating, number, uri } = jwt(user);

    const logout = () => {
        setUser(null);
        authStorage.removeToken();
    }

    console.log(`Uri: ${uri}`);

    return { user, setUser, logout, name, rating, number, uri };
}

现在我已经在我的 App.js 中创建了一个上下文,我从那里获取这个用户和 setUser 基本上是令牌。写这一行让我陷入了钩子错误。

请以两种方式帮助我:

  1. 请告诉我为什么会发生此错误,因为正如您所见,我没有违反任何钩子法则。
  2. 请告诉我是否做得对。

3 个答案:

答案 0 :(得分:2)

由于您的组件主体未调用您的 updateProfilePicture,因此您应该将其更改为将您的令牌作为参数接收。

然后在您的 Component 处,您可以在组件主体处调用钩子 useAuth,提取所需的标记。这样您就可以将它作为变量传递给 updateProfilePicture 而不会遇到任何错误,因为 useAuth 将在您的函数体中被正确调用。

你的代码看起来像:

const updateProfilePicture = (image, token) => {
  // ... same code here without 'useAuth'
}

const Component = ({ image }) => {
  const { user: token } = useAuth();

  const onsubmit = () => updateProfilePicture(img, token)

  return (
    <>
      <div>upload here image</div>
      <button onClick={() => onsubmit(image, token)}>upload</button>
    </>
  )
}

答案 1 :(得分:1)

react 功能组件中的钩子必须在主组件函数中使用或作为自定义钩子的一部分,没有条件、循环或回调。 您必须将 useAuth 钩子移至主要组件函数、try-catch 块之外和 updateProfilePicture 函数之外

答案 2 :(得分:0)

根据React Documentation

<块引用>

不要在循环、条件或嵌套函数中调用 Hook。相反,在任何提前返回之前,始终在 React 函数的顶层使用 Hook。通过遵循此规则,您可以确保每次渲染组件时以相同的顺序调用 Hook。这就是允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 状态的原因。

✅ 从 React 函数组件调用 Hooks。

✅ 从自定义 Hooks 调用 Hooks(我们将在下一页了解它们)。

您的 useAuth 钩子在 try-catch 块内被调用。相反,在功能组件的顶层调用它