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:
- You might have mismatching versions of React and the renderer (such as React DOM)
- You might be breaking the Rules of Hooks
- 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 ApolloProvider
from @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
</>