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

时间:2019-10-17 07:19:58

标签: javascript reactjs graphql react-hooks react-apollo

尝试从公共graphql api使用react-apollo时出现此错误。

  

无效的挂钩调用。钩子只能在   功能组件。可能发生以下情况之一   原因:

     
      
  1. 您可能使用的React和渲染器版本不匹配(例如React DOM)
  2.   
  3. 您可能正在违反挂钩规则
  4.   
  5. 您可能在同一应用中拥有多个React副本
  6.   

我已经读过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,现在代码如下:

Select.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:

时间越来越长,但是我已经从ApolloProvider中的@apollo/react-hooks导入了index.js来解决最后一个问题:

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

现在我得到

  

TypeError:数据未定义

app.js的这一行:

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

1 个答案:

答案 0 :(得分:0)

我在使用带有 graphqlnestjs API 的 react-apollo 时遇到了这个错误,我首先尝试了 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

所以我修复了如下代码所示:

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