I am trying to use a custom hook to call the API for fetching data. And then I am trying to call that hook in my Context API. The problem is that the body of the hook is being rendered 6 times. So then when I try to setState in my Context file using the data returned by the custom hook(useFetchData), I get the error - "Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.". I think some state change is causing it to re-render.
context.js
import React, { useState, createContext } from "react";
import useFetchData from './Custom Hooks/useFetchData'
export const Context = createContext();
export function Provider(props) {
let intialState = {
track_list: [],
heading: "",
loading: true
// dispatch: action => this.setState(state => reducer(state, action))
};
const [state, setState] = useState(intialState)
// Get Top 10 Tracks
const url = 'chart.tracks.get?chart_name=top&page=1&page_size=5&country=it&f_has_lyrics=1'
const [data, loading] = useFetchData(url)
// setState({ track_list: data, heading: "Top 10 Tracks", loading }) // Causes Too Many Re-renders.
return (
<Context.Provider value={[state, setState]}>{props.children}</Context.Provider>
);
}
useFetchData (Custom Hook)
import { useState, useEffect } from "react";
import axios from "axios";
function useFetchData(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
console.log('Rendering Again and Again');
useEffect(() => {
// Top 10 Tracks
async function fetchData(url) {
try {
const response = await axios.get(
`${url}&apikey=${process.env.REACT_APP_API_KEY}`
);
const data = await response.data.message.body;
console.log(data);
setData(data);
setLoading(false);
} catch (error) {
console.log(error);
}
}
fetchData(url);
}, [url]);
return [data, loading];
}
export default useFetchData;
Browser Logs
useFetchData.js:7 Rendering Again and Again
useFetchData.js:7 Rendering Again and Again
useFetchData.js:16 {track_list: Array(5)}
useFetchData.js:7 Rendering Again and Again
useFetchData.js:7 Rendering Again and Again
useFetchData.js:7 Rendering Again and Again
useFetchData.js:7 Rendering Again and Again
setState({ track_list: data, heading: "Top 10 Tracks", loading })
is causing an infinite number of re-renders because you're setting it in the body of the component, not in response to something, eg, a handler or an effect. So, each time through you're setting state, which results in a render, which then re-sets state, causing another render, ad infinitum.
Add a useEffect
in your provider to detect changes to the relevant data and set the state there. Something like,
useEffect(() => {
setState({ track_list: data, heading: "Top 10 Tracks", loading })
}, [loading, data])
This will only be called when loading
or data
is different than the last render.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.