挂钩调用无效。钩子只能在函数组件的内部调用

Invalid hook call. Hooks can only be called inside of the body of a function component

我想使用 React 在 table 中显示一些记录,但出现此错误:

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 for tips about how to debug and fix this problem.
import React, {
  Component
} from 'react';
import {
  makeStyles
} from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';

const useStyles = makeStyles(theme => ({
  root: {
    width: '100%',
    marginTop: theme.spacing(3),
    overflowX: 'auto',
  },
  table: {
    minWidth: 650,
  },
}));

class allowance extends Component {
  constructor() {
    super();
    this.state = {
      allowances: [],
    };

  }

  componentWillMount() {
    fetch('http://127.0.0.1:8000/allowances')
      .then(data => {

        return data.json();

      }).then(data => {

        this.setState({
          allowances: data
        });

        console.log("allowance state", this.state.allowances);
      })

  }



  render() {
    const classes = useStyles();
    return ( <
      Paper className = {
        classes.root
      } >
      <
      Table className = {
        classes.table
      } >
      <
      TableHead >
      <
      TableRow >
      <
      TableCell > Allow ID < /TableCell> <
      TableCell align = "right" > Description < /TableCell> <
      TableCell align = "right" > Allow Amount < /TableCell> <
      TableCell align = "right" > AllowType < /TableCell>

      <
      /TableRow> <
      /TableHead> <
      TableBody > {
        this.state.allowances.map(row => ( <
          TableRow key = {
            row.id
          } >
          <
          TableCell component = "th"
          scope = "row" > {
            row.AllowID
          } <
          /TableCell> <
          TableCell align = "right" > {
            row.AllowDesc
          } < /TableCell> <
          TableCell align = "right" > {
            row.AllowAmt
          } < /TableCell> <
          TableCell align = "right" > {
            row.AllowType
          } < /TableCell>                     <
          /TableRow>
        ))
      } <
      /TableBody> <
      /Table> <
      /Paper>
    );
  }

}

export default allowance;

React linter 假定每个方法都以 use 开头,因为钩子和钩子在 类 中不起作用。通过将 const useStyles 重命名为不以 use 开头的任何其他内容,例如 const myStyles 你就可以开始了。

更新:

makeStyles 是钩子 api,您不能在 类 中使用它。您可以使用样式化组件 API。参见 here

您只能从 React 函数中调用钩子。阅读更多 here.

只需将 Allowance class 组件转换为功能组件。

Working CodeSandbox demo.

const Allowance = () => {
  const [allowances, setAllowances] = useState([]);

  useEffect(() => {
    fetch("http://127.0.0.1:8000/allowances")
      .then(data => {
        return data.json();
      })
      .then(data => {
        setAllowances(data);
      })
      .catch(err => {
        console.log(123123);
      });
  }, []);

  const classes = useStyles();
  return ( <
    Paper className = {
      classes.root
    } >
    <
    Table className = {
      classes.table
    } >
    <
    TableHead >
    <
    TableRow >
    <
    TableCell > Allow ID < /TableCell> <
    TableCell align = "right" > Description < /TableCell> <
    TableCell align = "right" > Allow Amount < /TableCell> <
    TableCell align = "right" > AllowType < /TableCell> <
    /TableRow> <
    /TableHead> <
    TableBody > {
      allowances.map(row => ( <
        TableRow key = {
          row.id
        } >
        <
        TableCell component = "th"
        scope = "row" > {
          row.AllowID
        } <
        /TableCell> <
        TableCell align = "right" > {
          row.AllowDesc
        } < /TableCell> <
        TableCell align = "right" > {
          row.AllowAmt
        } < /TableCell> <
        TableCell align = "right" > {
          row.AllowType
        } < /TableCell> <
        /TableRow>
      ))
    } <
    /TableBody> <
    /Table> <
    /Paper>
  );
};

export default Allowance;

您可以将 class 组件转换为钩子,但是 Material v4 有一个 withStyles HOC。 https://material-ui.com/styles/basics/#higher-order-component-api 使用此 HOC,您可以保持代码不变。

昨天,我缩短了代码(刚添加<Provider store={store}>),仍然遇到这个无效的挂钩调用问题。这让我突然意识到我犯了什么错误:我没有在那个文件夹里安装react-redux软件。

我把这个软件安装在另一个项目文件夹中,所以我没有意识到这个也需要它。安装后错误消失

我刚开始使用钩子,当我在函数中调用 useEffect 时收到上述警告:

然后我必须将 useEffect 移出函数,如下所示:

 const onChangeRetypePassword = async value => {
  await setRePassword(value);
//previously useEffect was here

  };
//useEffect outside of func 

 useEffect(() => {
  if (password !== rePassword) {
  setPasswdMismatch(true);

     } 
  else{
    setPasswdMismatch(false);
 }
}, [rePassword]);

希望对大家有所帮助!

如果上述所有方法都不起作用,特别是如果具有较大的依赖性(如我的情况),则构建和加载至少需要 15 秒,因此延迟似乎给出了错误消息 "Invalid hook call." 所以你能做的就是给一些时间来确保在测试之前完成构建。

您可以通过调用箭头函数来使用 "export default",returns 它的 React.Component 通过 MaterialUI class 对象道具传递它,这又将被使用在 Component render ().

class AllowanceClass extends Component{
    ...
    render() {
        const classes = this.props.classes;
        ...
    }
}

export default () => {
    const classes = useStyles();
    return (
        <AllowanceClass classes={classes} />
    )
}

发现此错误:已找到解决方案。

出于某种原因,我的标签上有 2 个 onClick 属性。 使用您或某些人的自定义组件时要小心,也许其中一些已经具有 onClick 属性。

对我来说,错误是在函数默认导出之外调用函数 useState

就我而言,我试图在 windows 上使用 mdbreact。虽然它安装了,但我收到了上述错误。我不得不重新安装它,一切正常。我用 antd Library

遇到过一次

我在使用 npm link 安装我使用 cra 构建的本地库时遇到了这个问题。我找到了答案 here。字面意思是:

This problem can also come up when you use npm link or an equivalent. In that case, your bundler might “see” two Reacts — one in application folder and one in your library folder. Assuming 'myapp' and 'mylib' are sibling folders, one possible fix is to run 'npm link ../myapp/node_modules/react' from 'mylib'. This should make the library use the application’s React copy.

因此,运行 命令:npm link <path_to_local_library>/node_modules/react,例如。在我的例子中,项目目录中的 npm link ../../libraries/core/decipher/node_modules/react 已经解决了这个问题。

我的情况.... HOOKS

中的解决方案
const [cep, setCep] = useState('');
const mounted = useRef(false);

useEffect(() => {
    if (mounted.current) {
        fetchAPI();
      } else {
        mounted.current = true;
      }
}, [cep]);

const setParams = (_cep) => {
    if (cep !== _cep || cep === '') {
        setCep(_cep);
    }
};

当您以错误的方式从 react-redux 声明 useDispatch 时,也会发生此错误: 当你去的时候:
const dispatch = useDispatch 而不是:
const dispatch = useDispatch(); (即记得添加括号)

对于使用 redux 的人:

class AllowanceClass extends Component{
    ...
    render() {
        const classes = this.props.classes;
        ...
    }
}
    
const COMAllowanceClass = (props) =>
{
    const classes = useStyles();
    return (<AllowanceClass classes={classes} {...props} />);
};

const mapStateToProps = ({ InfoReducer }) => ({
    token: InfoReducer.token,
    user: InfoReducer.user,
    error: InfoReducer.error
});
export default connect(mapStateToProps, { actions })(COMAllowanceClass);

当您使用依赖项而不安装它时也会发生。 当我在项目中丢失时从“@material-ui/icons/”调用 MenuIcon 时发生在我身上。

我的共享库之间的不同版本的反应似乎是问题所在(16 和 17),都更改为 16。

如果您使用的是 mobx,并且您的功能组件包含在 mobx observer 函数中,也会发生此错误。如果是这种情况,请确保您使用的是 mobx-react 版本 6.0.0 或更高版本。旧版本会在幕后将您的功能组件转换为 class,并且所有挂钩都将失败并出现此错误。

在这里查看答案:

将此添加到您的 package.json

"peerDependencies": {
   "react": ">=16.8.0",
   "react-dom": ">=16.8.0"
}

来源:https://robkendal.co.uk/blog/2019-12-22-solving-react-hooks-invalid-hook-call-warning

对于可能正在寻找此问题的快速解决方案的任何人:

您可能违反了 Hooks 规则。 要解决此问题,请移动 :

const [x, setX] = useState(0);

到调用它的函数的顶层而不是函数之外。

function App() {
   const [t, setTime] = useState("");

   return (
      <div>
         <h1>{t}</h1>
         <button onClick={() => setTime(t+1)}>Get Time</button>
      </div>
 );
}

https://reactjs.org/warnings/invalid-hook-call-warning.html

我遇到这个问题,我的错误原因是我开发项目A,我link另一个项目B给A,但是A有React包,B也有React包,他们是同一个版本(16.13)。 但这引起了问题,我将文件设置为 webpack.config.js,如下所示:

alias: {
  'react': path.join(path.resolve(__dirname), '../node_modules/react'),
},

set B React package resolve to A React package,我猜原因是一个项目不能有两个或多个React package,即使它们是相同的版本。但我无法验证我的猜测。

这是为我解决的问题。我的组件文件夹以及它所属的项目的根目录中有文件夹 node_modules 和文件 package.json 和 package-lock.json。我从他们不属于的地方删除了他们。不要问我做了什么把它们放在那里,我一定是从错误的位置做了一个 npm 东西。

在我的例子中,我在 FlatListrenderItem 属性中传递组件名称而不是函数。由于我的组件是一个功能组件,所以它可以更早地工作,但是当我在其中添加挂钩时,它失败了。

之前:

    <FlatList
        data={memberList}
        renderItem={<MemberItem/>}
        keyExtractor={member => member.name.split(' ').join('')}
        ListEmptyComponent={
          <Text style={{textAlign: 'center', padding: 30}}>
            No Data: Click above button to fetch data
          </Text>
        }
      />

之后:

    <FlatList
        data={memberList}
        renderItem={({item, index}) => <MemberItem item={item} key={index} />}
        keyExtractor={member => member.name.split(' ').join('')}
        ListEmptyComponent={
          <Text style={{textAlign: 'center', padding: 30}}>
            No Data: Click above button to fetch data
          </Text>
        }
      />

在我的例子中,我从两个项目中删除了 package-lock.jsonnode_modules,然后重新安装,现在工作正常。


// project structure


root project
- package-lock.json
- package.json // all dependencies are installed here
- node_modules

-- second project
-- package-lock.json
-- package.json 
  "dependencies": {
    "react": "file:../node_modules/react",
    "react-dom": "file:../node_modules/react-dom",
    "react-scripts": "file:../node_modules/react-scripts"
  },
-- node_modules


不确定最初是什么原因导致了这个问题,因为我以前也遇到过这种情况,按照上面的步骤操作,问题就解决了。

就我而言,我在 package-json 中所做的更改导致了问题。

npm install react-redux

解决这个问题

如果您使用的是 react-router-dom,请务必在钩子内调用 useHistory()。

您可以检查您的路线。如果您在 Route(} />) 中使用渲染而不是组件 所以你在箭头函数中正确地调用了你的组件,并向其传递了适当的道具。

注意导入问题 - 对我来说,错误是关于组件和子组件的导入/自动导入失败。与功能 类 与 Class 组件无关。

  • 这很容易发生,因为 VS 代码自动导入可以指定不起作用的路径。
  • 如果使用导入 { MyComponent } 并且在组件中使用 export default 导入应该说 import MyComponent
  • 如果某些组件在其文件夹内使用 index.js 作为路径的快捷方式,而其他组件则不使用,则导入可能会中断。这里再次自动导入可能会导致问题,因为它将所有组件合并到与此 {TextComponent, ButtonComponent, ListComponent} from '../../common'
  • 相同的文件夹中

尝试注释掉出现错误的文件中的一些组件,您可以测试是否是问题所在。

当你遇到这个问题时,你只需要重新安装这个“npm install react-bootstrap@next bootstrap@5.1.0”,你的错误就会得到解决。

就我而言,正是我 App.js 上的这一行代码导致了这种情况,并让我在调试中损失了 10 个小时。 React Native 和 Expo 无法指出这一点。我做了 Whosebug 和 github 上的所有操作,甚至是本应解决此问题的反应页面,但问题仍然存在。我不得不开始一点一点地分解我的代码以找出罪魁祸首

 **const window = useWindowDimensions();**

它是这样放置的:

import * as React from 'react';
import { Text, View, StyleSheet, ImageBackground, StatusBar, Image, Alert, SafeAreaView, Button, TouchableOpacity, useWindowDimensions } from 'react-native';
import Constants from 'expo-constants';

import Whooksplashscreen11 from './Page1';
import Screen1 from './LoginPage';
import Loginscreen from './Login';
import RegisterScreen1 from './register1';
import RegisterScreen2 from './register2-verifnum';
import RegisterScreen3 from './register3';
import RegisterScreen4 from './register4';
import RegisterScreen5 from './register5';
import RegisterScreen6 from './register6';
import BouncyCheckbox from "react-native-bouncy-checkbox";
import LocationPermission from './LocationPermission.js'
import Selfieverif1 from './selfieverif1'
import Selfieverif2 from './selfieverif2'
import AddPhotos from './addphotos'


// You can import from local files
import { useFonts } from 'expo-font';

// or any pure javascript modules available in npm

import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';


//FontAwesome
import { library } from '@fortawesome/fontawesome-svg-core'
import { fab, } from '@fortawesome/free-brands-svg-icons'
import { faCheckSquare, faCoffee, faFilter, faSearch,  } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome'
import Icon  from "react-native-vector-icons/FontAwesome5";

import MyTabs from './swipepage'

library.add(fab, faCheckSquare, faCoffee, faFilter, faSearch,);


const window = useWindowDimensions();
const Stack = createNativeStackNavigator();

function App() {
  return ( ....
)}

就我而言,问题是我将 cd 放入了错误的目录以进行 npm 安装。我只是 re-installed 正确目录中的库,它工作正常!

我 运行 遇到了类似的问题,但是我的情况有点极端。

接受的答案应该适用于大多数人,但对于在使用 Radium 的现有 React 代码中使用 React Hooks 的任何其他人来说,请注意,如果您使用 radium,如果没有变通办法,Hooks 将无法工作。

就我而言,我是这样导出我的组件的:

// This is pseudocode

const MyComponent = props => {
  const [hookValue, setHookValue] = useState(0);
  return (
    // Use the hook here somehow
  )
}

export default Radium(MyComponent)

export 中删除 Radium 包装器解决了我的问题。如果您需要 使用 Radium,使用 class 组件及其生命周期函数可能是更简单的解决方案。

希望这至少能帮助到另外一个人。

我 运行 在处理自定义 node_module 并使用 npm linkcra(创建 React 应用程序)中进行测试时遇到了同样的问题。

我发现在我的习惯 node package 中,我必须添加一个 peerDependencies

"peerDependencies": {
    "@types/react": "^16.8.6 || ^17.0.0",
    "react": "^17.0.0",
    "react-dom": "^17.0.0"
  },

将其添加到我的 package.json 后,我然后 re-built 我的自定义包。 然后在CRA,我吹走了node_modules,重新npm install,Re-do npm link <package>,然后开始工程

已修复一切!

如果您的 front-end 作品在其自己的文件夹中,您可能需要在该文件夹中安装 @material-ui/core @material-ui/icons,而不是在后端文件夹中。

npm i @material-ui/core @material-ui/icons

我的错误是最后的导出,我有以下内容:

我应该去掉括号:

链接本地图书馆时出现此错误。以下解决了我的问题。

  1. 在图书馆:
  • 从依赖项中删除“react”和“react-dom”并将它们添加到 peerDependencies。
  • 安装依赖,构建
  1. 重新启动主项目。

可能发生此错误的另一个原因是,如果您使用箭头函数签名而不是函数签名来声明功能组件。

例如: 从箭头函数更改功能组件声明

export const Counter = (props) => {}

TO函数声明

export function Counter (props) {}

这将有助于解决问题。 至少就我而言,它做到了。