So I was trying to fetch some anime data based on the options I have in select (genre),
the problem is that the fetch doesn’t happen onChange in my select only after changing option twice, I have tried to use useEffect but the problem with that it’s fetching immediately without changing the select value.
can someone help and explain what I’m doing wrong?
here is my code on codesandbox
index.js
function App() {
const [list,setList]=useState([])
const [genre,setGenre]=useState(0)
const fetchData=()=>{
const options = {
method: 'GET',
url: `https://jikan1.p.rapidapi.com/genre/anime/${genre}/1`,
headers: {
'x-rapidapi-host': 'jikan1.p.rapidapi.com',
'x-rapidapi-key': '*******************************'
}
};
axios.request(options).then(function (response) {
console.log(response.data.anime);
setList(response.data.anime)
}).catch(function (error) {
console.error(error);
});
}
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData()
}
return (
<div className="mx-auto px-8 py-4 flex flex-col justify-center">
<div>
<h1>Design with Tailwind</h1>
<select name="genre" className='p-2 bg-bg-prime' id="genre" onChange={handleChange}>
<option value="1" >Action</option>
<option value="2" >Adventure</option>
<option value="4" >Comedy</option>
</select>
</div>
<div>
{list && (
list.map((an)=>(
<p key={an.title}>{an.title}</p>
))
)}
</div>
</div>
)
}
const rootElement = document.getElementById('root')
ReactDOM.render(<App />, rootElement)
>Solution :
While you are calling fetchData after the setGenre, according to react docs :
State Updates May Be Asynchronous
So basically fetchData is called before the state value is actually updated (and this is causing your request to be performed with the old value instead of the requested one).
A fix would be something like:
...
useEffect(() => {
fetchData();
}, [genre])
const handleChange=(e)=>{
setGenre(e.target.value)
}
If you really want to keep your approach you could also do something like:
const handleChange=(e)=>{
setGenre(e.target.value)
fetchData(e.target.value)
}
and use the variable in fetch data (so
const fetchData = (selectedGenre) => {
...
url: `https://jikan1.p.rapidapi.com/genre/anime/${selectedGenre}/1`,
...
I personally prefer first approach, but both should work.
Also if you use a valid value as the initial value for the genre along with the first approach you can get the list populated by default (for your example const [genre,setGenre]=useState(1) )