React Native 错误:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用

Posted

技术标签:

【中文标题】React Native 错误:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用【英文标题】:React Native Error: Invalid hook call. Hooks can only be called inside of the body of a function component 【发布时间】:2022-01-09 19:41:32 【问题描述】:

我正在和一些朋友编写一个国际象棋应用程序,现在我们在实现国际象棋本身时遇到了错误。 我们在函数的第一个 const 以及 App.jsx 的导出中得到错误

我们的 GitHub 存储库:Chedu

App.jsx

import React,  useEffect, useState  from "react";
import "./App.css";
import  gameSubject, initGame, resetGame  from "./Game";
import Board from "./Board";

function App() 
  const [board, setBoard] = useState([]); //get Error here
  const [isGameOver, setIsGameOver] = useState();
  const [result, setResult] = useState();
  const [turn, setTurn] = useState();

  useEffect(() => 
    initGame();
    const subscribe = gameSubject.subscribe((game) => 
      setBoard(game.board);
      setIsGameOver(game.isGameOver);
      setResult(game.result);
      setTurn(game.turn);
    );
    return () => subscribe.unsubscribe();
  , []);

  return (
    <div className="container">
      isGameOver && (
        <h2 className="vertical-text">
          GAME OVER
          <button onClick=resetGame>
            <span className="vertical-text"> NEW GAME</span>
          </button>
        </h2>
      )
      <div className="board-container">
        <Board board=board turn=turn />
      </div>
      result && <p className="vertical-text">result</p>
    </div>
  );

export default App(); //Error Anonymous Function

在 Index.js 中,我们正在渲染函数并将其导出。

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import * as serviceWorker from "./serviceWorker";
import  DndProvider  from "react-dnd";
import  html5Backend  from "react-dnd-html5-backend";
export default ReactDOM.render(
  <React.StrictMode>
    <DndProvider backend=HTML5Backend>
      <App />
    </DndProvider>
  </React.StrictMode>,
  document.getElementById("root")
);

serviceWorker.unregister();

最后我们要在 ChessBoardPage 中渲染 index.js

import React,  useState  from "react";
import 
  StyleSheet,
  Text,
  View,
  Image,
  TouchableOpacity,
  Dimensions,
  Switch,
 from "react-native"; //components

import ReactDOM from "react-dom";

import cheduLogo from "../Pictures/Logo.png";
import loginPictureBlack from "../Pictures/login.png";
import loginPictureWhite from "../Pictures/login_white.png";
import registerPictureBlack from "../Pictures/register.png";
import registerPictureWhite from "../Pictures/register_white.png";
import userPictureBlack from "../Pictures/user.png";
import userPictureWhite from "../Pictures/user_white.png";

import ChessGame from "./ChessBoard/index";

const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;

const  width  = Dimensions.get("window");

const x = 100;
const y = 200;

export default class TempPage extends React.Component 
  state = 
    switchValue: false,
    backgroundColor: "white",
    SwitchLogin: loginPictureBlack,
    SwitchRegister: registerPictureBlack,
    SwitchUser: userPictureBlack,
    SunMoon: "☀️",
    ShadowBackgroundColor: "white",
  ;

  handleSwitchBackground = () => 
    [...]
    
  ;

  render() 
    let  backgroundColor  = this.state;
    return (
      <View
        style=
          windowWidth,
          windowHeight,
          backgroundColor: this.state.backgroundColor,
        
      >
          
        [...]

        /*Content*/
        <View stlye= flex: 1 >
          <ChessGame />
        </View>
      </View>
    );
  

[...]

【问题讨论】:

小错误 export default App 不是 export default App() - 不要调用函数 【参考方案1】:

有时我们在使用匿名函数时会遇到问题。因为匿名函数没有被分配一个标识符(通过 const/let/var),所以只要这个函数组件不可避免地再次被渲染,它们就不是持久的。这会导致 javascript 在每次重新渲染此组件时分配新内存,而不是在使用“命名函数”时仅分配一次内存 考虑重构你的代码如下

import React,  useEffect, useState  from "react";
import "./App.css";
import  gameSubject, initGame, resetGame  from "./Game";
import Board from "./Board";

const App = () => 
  const [board, setBoard] = useState([]); //get Error here
  const [isGameOver, setIsGameOver] = useState();
  const [result, setResult] = useState();
  const [turn, setTurn] = useState();

  useEffect(() => 
    initGame();
    const subscribe = gameSubject.subscribe((game) => 
      setBoard(game.board);
      setIsGameOver(game.isGameOver);
      setResult(game.result);
      setTurn(game.turn);
    );
    return () => subscribe.unsubscribe();
  , []);

  return (
    <div className="container">
      isGameOver && (
        <h2 className="vertical-text">
          GAME OVER
          <button onClick=resetGame>
            <span className="vertical-text"> NEW GAME</span>
          </button>
        </h2>
      )
      <div className="board-container">
        <Board board=board turn=turn />
      </div>
      result && <p className="vertical-text">result</p>
    </div>
  );
;
export default App;

我不确定你为什么在 react native 中使用 HTML 标签,这在App.jsx 中尚不支持。您应该返回 &lt;View/&gt; 标签而不是 div。

【讨论】:

以上是关于React Native 错误:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用的主要内容,如果未能解决你的问题,请参考以下文章

React - 错误:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用

React + Antd + Rollup 组件库“错误:无效的钩子调用。钩子只能在函数组件的主体内部调用”

React 17:错误:无效的钩子调用。 Hooks 只能在函数组件的主体内部调用

react-native 和 yarn 工作区的“钩子只能在函数组件的主体内调用”错误

react-intl 与 react-testing-library 给出了无效的钩子调用错误

反应无效的钩子调用错误和故事书6