I am learning React by making a motor cycle spec searching web application, and I am trying to import fetched data into makePicker.jsx
to essentially make a drop down menu with those data.
However I am getting an error message saying:
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 am not sure what applies to my situation. Can you see why?
makePicker.jsx
import React, {useState, useEffect} from 'react';
import {NativeSelect, FormControl} from '@material-ui/core';
import styles from './makePicker.module.css';
import { makeList } from '../../api';
const MakePicker = ()=>{
const [fetchedMakes, setFetchedMakes] = useState([]);
useEffect(()=>{
const fetchAPI = async()=>{
setFetchedMakes(await makeList());
}
fetchAPI();
},[])
return (
<h1>makePicker</h1>
);
}
export default MakePicker;
App.js
import logo from './logo.svg';
import './App.css';
import {fetchData, makeList} from './api/index';
import React, {Component} from 'react';
import MakePicker from './components/makePicker/makePicker';
class App extends React.Component{
state = {
data:[],
makes:[],
}
async componentDidMount(){
// const fetchedData = await fetchData();
const fetchedMakeList = await makeList();
this.setState({makes:fetchedMakeList});
}
render(){
return (
<div className="App">
<header className="App-header">
{MakePicker()};
<h1>Some line-ups from YAMAHA</h1>
{this.state.makes.map(make=>{
return <p>{make.name}</p>
})}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Open React
</a>
</header>
</div>
);
}
}
export default App;
Please let me know if need more information from my project.
CodePudding user response:
According to your code in App.jsx
and following the naming convention of React's component, you should import it with the first-capitalized-letter name like below
import MakePicker from './components/makePicker/makePicker';
You're also calling {makePicker()};
which is not a proper way for component rendering. You should modify it to
<MakePicker/>
Full possible change can be
import logo from './logo.svg';
import './App.css';
import {fetchData, makeList} from './api/index';
import React, {Component} from 'react';
import MakePicker from './components/makePicker/makePicker';
class App extends React.Component{
state = {
data:[],
makes:[],
}
async componentDidMount(){
// const fetchedData = await fetchData();
const fetchedMakeList = await makeList();
this.setState({makes:fetchedMakeList});
}
render(){
return (
<div className="App">
<header className="App-header">
<MakePicker/>
<h1>Some line-ups from YAMAHA</h1>
{this.state.makes.map(make=>{
return <p>{make.name}</p>
})}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Open React
</a>
</header>
</div>
);
}
}
export default App;
To elaborate more why you get this error
Invalid hook call. Hooks can only be called inside of the body of a function component.
When you call makePicker()
, it's actually triggering a Javascript's function (not React's component as you expected), but useEffect
is only available in React's components. That's why when you try to run code, the compiler is thinking makePicker
is calling useEffect
invalidly.
CodePudding user response:
Their is a problem lies on your useEffect
update the code like this and try it out:
const fetchAPI = async()=>{
const res = await makeList().then((data) => {
setFetchedMakes(data)
}).catch((err) => console.log(err))
}
useEffect(()=>{
fetchAPI();
},[])
here i placed the asynchronous function outside of the useEffect
Also make MakePicker as an JSX element like this: <MakePicker />