5

I get this error trying to use react-apollo from a public graphql api.

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

I've read react documentations and I'm sure the problem is not one of those three reasons.

It's a simple project using create-react-app. Both react and react-dom versions are 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")
);

I'm new to graphql and apollo and have no idea what could be the reason for this error.

Update

As @Joseph suggested, I've extracted a component out of app and used useQuery, and now the code looks like this:

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;

No changing in index.js, But I still get the same error.

Update 2:

I was missing installing @apollo/react-hooks but twhen I installed it, I got a new error now:

Could not find "client" in the context or passed in as an option. Wrap the root component in an , or pass an ApolloClient instance in via options.

Update 3:

This is getting long but I've imported ApolloProviderfrom @apollo/react-hooks in index.js to fix the last issue:

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

And now i get

TypeError: data is undefined

In this line from app.js:

  <>
   {loading && <p>Loading...</p>}
   {error &&  <p>{error.message}</p>}
   <Select countries={data.countries} />  // <= This line causes error
  </>
Ghasem
  • 14,455
  • 21
  • 138
  • 171
  • 1
    There's nothing wrong withe first code you provided. If you have an error, it's elsewhere. Here's the exact same code running fine in codesandbox: https://codesandbox.io/s/confident-snowflake-kdyik – Marouane Fazouane Oct 17 '19 at 08:47
  • @MarouaneFazouane But it's all the project so far, Could be codesandbox be different with `create-react-app` in something? – Ghasem Oct 17 '19 at 08:51
  • I don't think so. Try stopping then re-running `yarn start` or something? – Marouane Fazouane Oct 17 '19 at 08:57
  • @MarouaneFazouane This left me with second error in update 2 – Ghasem Oct 17 '19 at 09:00
  • @AlexJolig `{ data && data.countries && }` – Joseph D. Oct 17 '19 at 09:17
  • @JosephD. wOw!! Finally! What does this line means? Also why did you remove the answer? It works now! – Ghasem Oct 18 '19 at 07:51
  • 1
    @AlexJolig it's ok. I don't feel showing long answers. lol Anyway, the line basically is a [conditional render](https://reactjs.org/docs/conditional-rendering.html). Would need to ensure that `data` **and** `data.countries` are both defined (not null) to be able to render the `Select` component. Happy to know everything is fine now. – Joseph D. Oct 18 '19 at 08:01
  • @JosephD. Thanks man! – Ghasem Oct 18 '19 at 16:39

1 Answers1

0

I've got this error while I was using react-apollo with the graphql API made with nestjs, I have tried first 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

So I have fixed like is shown in the code below:

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
L3xpert
  • 1,109
  • 1
  • 10
  • 19