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

Posted

技术标签:

【中文标题】无效的挂钩调用。钩子只能在使用 react-apollo 的函数组件内部调用【英文标题】:Invalid hook call. Hooks can only be called inside of the body of a function component using react-apollo 【发布时间】:2020-02-14 01:00:06 【问题描述】:

我在尝试使用来自公共 graphql api 的 react-apollo 时遇到此错误。

无效的挂钩调用。 Hooks 只能在 a 的主体内部调用 功能组件。这可能发生在以下情况之一 原因:

    您的 React 和渲染器版本可能不匹配(例如 React DOM) 您可能违反了 Hooks 规则 您可能在同一个应用中拥有多个 React 副本

我已阅读 react documentations,我确信问题不是这三个原因之一。

这是一个使用create-react-app 的简单项目。 reactreact-dom 版本都是 16.10.2

app.js:

import React, useState from 'react';
import  Query  from "react-apollo";
import  gql  from "apollo-boost";

const query = gql`
  
    countries 
      name
      code
    
  
`;

function App() 
    const [country, setCountry] = useState('US');
    const onCountryChange = event => 
      setCountry(event.target.value);
    ;

    return (
      <div className="App">
        <Query query=query>
          result => 
            if (result.loading) return <p>Loading...</p>;
            if (result.error) return <p>result.error.message</p>;
            return (
              <select value=country onChange=onCountryChange>
                result.data.countries.map(country => (
                  <option key=country.code value=country.code>
                    country.name
                  </option>
                ))
              </select>
            );
          
        </Query>
      </div>
    );

export default App;

index.js:

import React, useState from 'react';
import ReactDOM from 'react-dom';
import App from "./app";
import ApolloClient from 'apollo-boost';
import  ApolloProvider  from "react-apollo";

const client = new ApolloClient(
  uri: 'https://countries.trevorblades.com'
);

ReactDOM.render(
  <ApolloProvider client=client>
    <App />
  </ApolloProvider>,
  document.getElementById("root")
);

我是 graphql 和 apollo 的新手,不知道这个错误可能是什么原因。

更新

正如@Joseph 建议的那样,我从应用程序中提取了一个组件并使用了useQuery,现在代码如下所示:

选择.js:

import React, useState from 'react';

function Select(props) 
  const [country, setCountry] = useState('US');
  const onCountryChange = event => 
    setCountry(event.target.value); // already called within the function component
  ;

  return (
    <select value=country onChange=onCountryChange>
      props.countries.map(country => (
        <option key=country.code value=country.code>
          country.name
        </option>
      ))
    </select>
  );

export default Select;

app.js:

import React from 'react';
import  Query  from "react-apollo";
import  gql  from "apollo-boost";
import  useQuery  from '@apollo/react-hooks';
import Select from './select';

const query = gql`
  
    countries 
      name
      code
    
  
`;

function App() 
  const  loading, error, data  = useQuery(query);

  return (
    <div className="App">
      <>
       loading && <p>Loading...</p>
       error &&  <p>error.message</p>
       <Select countries=data.countries />
      </>
    </div>
  );

export default App;

index.js 没有变化,但我仍然遇到同样的错误。

更新 2:

我错过了安装@apollo/react-hooks,但是当我安装它时,我现在遇到了一个新错误:

在上下文中找不到“客户端”或作为选项传入。裹 中的根组件,或传递 ApolloClient 通过选项中的实例。

更新 3:

这有点长,但我已将 ApolloProviderfrom @apollo/react-hooks 导入 index.js 以修复最后一个问题:

import  ApolloProvider  from "@apollo/react-hooks";

现在我明白了

类型错误:数据未定义

在这行来自app.js:

  <>
   loading && <p>Loading...</p>
   error &&  <p>error.message</p>
   <Select countries=data.countries />  // <= This line causes error
  </>

【问题讨论】:

您提供的第一个代码没有任何问题。如果你有错误,它在其他地方。这是在代码框中运行良好的完全相同的代码:codesandbox.io/s/confident-snowflake-kdyik @MarouaneFazouane 但到目前为止,这就是所有项目,codesandbox 可能与create-react-app 有所不同吗? 我不这么认为。尝试停止然后重新运行yarn start 或其他什么? @MarouaneFazouane 这给我留下了更新 2 中的第二个错误 @AlexJolig 没关系。我不觉得显示长答案。大声笑无论如何,这条线基本上是conditional render。需要确保data data.countries 都已定义(非空)才能呈现Select 组件。很高兴知道现在一切都很好。 【参考方案1】:

我在使用 react-apollo 时遇到了这个错误

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:You might have mismatching versions of React and the renderer (such as React DOM)You might be breaking the Rules of HooksYou might have more than one copy of React in the same app

所以我已经修复如下代码所示:

Home.js

import  useLazyQuery, useMutation  from '@apollo/client'
import React,  useEffect, useState  from 'react'
import   GET_ALL_PROJECTS  from '../graphql/Queries'
function Home() 
    const [getEmployees,  loading, data, error ] = useLazyQuery(GET_ALL_PROJECTS,
        
            variables: 
        );

    if (error) 
        console.log(error)
    
    if (data) 
        console.table(data)
    
    useEffect(() => 
               getEmployees();
            , []);
return (
        <div className="home">...</div>


export default Home

【讨论】:

以上是关于无效的挂钩调用。钩子只能在使用 react-apollo 的函数组件内部调用的主要内容,如果未能解决你的问题,请参考以下文章

错误:无效的挂钩调用。钩子只能在函数组件的主体内部调用。 【我还在用函数组件】

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

× 错误:无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用。[ReactJS]

“无效的钩子调用。只能在函数组件的主体内部调用钩子”问题

useRef() 无效的钩子调用 [NextJs]

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