首页 > 解决方案 > 无效的挂钩调用。钩子只能在使用 react-apollo 的函数组件内部调用

问题描述

我尝试从公共graphql api使用 react-apollo 时收到此错误。

无效的挂钩调用。钩子只能在函数组件的主体内部调用。这可能由于以下原因之一而发生:

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

我已经阅读了反应文档,我确信问题不是这三个原因之一。

这是一个使用create-react-app. reactreact-dom版本都是16.10.2.

应用程序.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 建议的那样,我已经从 app 中提取了一个组件并使用了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;

应用程序.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:

这越来越长,但我已经ApolloProvider@apollo/react-hooksin导入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
  </>

标签: javascriptreactjsgraphqlreact-hooksreact-apollo

解决方案


我在使用 react-apollo 和graphqlAPI 制作时遇到了这个错误nestjs,我先尝试过componentWillMount()

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

所以我已经修复了,如下面的代码所示:

主页.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

推荐阅读