I am trying to generate a CustomHook that receives a function in charge of performing the query. The CustomHook should perform the query and return it.
ISSUE: When I change the parameter, it is not reflected in the component on the first click. Try putting the object with the parameters in the useEffect and it loops forever
Expected: Change a parameter from the front and automatically through useEffect or by executing a function, make the query again with the new parameter stored in a hook.
(The parameter must be an array, it is a function that I want to reuse)
Actual https://codesandbox.io/s/usefetchwithrefetch-iw4r33?file=/src/App.js:739-745
App.js
import { useState } from "react";
import "./styles.css";
import useFetch from "./useFetch";
export default function App() {
const url = "https://api.agify.io/";
const fetcher = (urlToFetch) => {
return fetch(urlToFetch);
};
const getYearByName = async (name) => {
const response = await fetcher(url + `?name=${name}`, {
method: "GET"
});
return await response.json();
};
const [name, setName] = useState("Nahuel");
const { data, isLoading, getData } = useFetch([name], getYearByName);
return (
<div className="App">
<button onClick={() => {
setName("Camila")
getData()}}>
Change name
</button>
{isLoading ? (
<div> cargando </div>
) : (
<>
<h1>{data.name}</h1>
<h2>{data.age}</h2>
</>
)}
</div>
);
}
useFetch.js
import { useState, useEffect } from "react";
const useFetch = (obj, functionTest) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const getData = async () => {
setIsLoading(true);
const response = await functionTest(...obj);
setData(response);
setIsLoading(false);
setError(false);
};
useEffect(() => {
getData();
}, []);
return {
data,
error,
isLoading,
getData
};
};
export default useFetch;
What you did is good.The infinite loop happened because you create a new value [name]
on each call!
import { useState, useEffect } from "react";
const useFetch = (obj, functionTest) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const getData = async () => {
setIsLoading(true);
const response = await functionTest(...obj);
setData(response);
setIsLoading(false);
setError(false);
};
useEffect(() => {
getData();
}, [obj]);
return {
data,
error,
isLoading,
getData
};
};
export default useFetch;
Additionally, obj
should be memoized on the caller side
const obj = useMemo(() => ([name]), [name]);