Multiple requests with useFetch - reactjs

Im sending 2 requests at the same time using useFetch, on Safari the responses are getting mixed
const [entries,setEntries] = useState([]);
const [categories,setCategories] = useState([]);
const { get, response} = useFetch('https://api.publicapis.org');
const getData = useCallback( async()=>{
const entriesRes = await get('/entries?category=animals&https=true')
if(response.ok)
setEntries(entriesRes.entries)
},[])
const getCategories = useCallback( async()=>{
const categoriesRes = await get('/categories')
if(response.ok)
setCategories(categoriesRes)
},[])
useEffect(()=>{
getData();
getCategories();
},[])
if the getCategories returns first the response go to entriesRes instand of categoriesRes this happens only on safari

Try renaming the useFetch results:
const [entries,setEntries] = useState([]);
const [categories,setCategories] = useState([]);
const categoryFetch = useFetch('https://api.publicapis.org');
const dataFetch = useFetch('https://api.publicapis.org');
const getData = useCallback( async()=>{
const entriesRes = await dataFetch.get('/entries?category=animals&https=true')
if(response.ok)
setEntries(entriesRes.entries)
},[])
const getCategories = useCallback( async()=>{
const categoriesRes = await categoryFetch.get('/categories')
if(response.ok)
setCategories(categoriesRes)
},[])
useEffect(()=>{
getData();
getCategories();
},[])

Related

Can i fetch multiple API and set states between api calls? (React and axios)

I want to fetch api and set state, then fetch another api with the state that comes from first one. So is that possible ?
Here is my code that i struggle with ;
useEffect(()=>{
const fetchPokemonSpecies = async (pokemon) => {
const data = await axios("https://pokeapi.co/api/v2/pokemon-species/"+pokeName).then( (response) =>
axios(response.data.evolution_chain.url)).then((response) => {setPokemonFirstEvolution(response.data.chain.evolves_to[0].species.name)
setPokemonFirstForm(response.data.chain.species.name)
setPokemonSecondEvolution(response.data.chain.evolves_to[0].evolves_to[0].species.name)})
setPokemonSpecies(data)
setPokemonCategory(data.genera[7].genus)
}
Thanks already !
So i just solve my problem this way ;
const [pokemonCategory, setPokemonCategory] = useState([])
const [pokemonSecondEvolution, setPokemonSecondEvolution] = useState([])
const [pokemonFirstEvolution, setPokemonFirstEvolution] = useState([])
const [pokemonFirstForm, setPokemonFirstForm] = useState([])
const [pokemonFirstFormIcon, setPokemonFirstFormIcon] = useState([])
const [pokemonFirstEvoIcon, setPokemonFirstEvoIcon] = useState([])
const [pokemonSecondEvoIcon, setPokemonSecondFormIcon] = useState([])
useEffect(()=>{
const fetchPokemonSpecies = async (pokemon) => {
const data = await axios("https://pokeapi.co/api/v2/pokemon-species/"+pokeName).then( (response) => response.data)
setPokemonSpecies(data)
setPokemonCategory(data.genera[7].genus)
const data2 = await axios(data.evolution_chain.url).then((response) => axios("https://pokeapi.co/api/v2/pokemon/"+response.data.chain.evolves_to[0].species.name))
setPokemonFirstEvoIcon(data2.data.sprites.other.dream_world.front_default)
const data3 = await axios(data.evolution_chain.url).then((response) => axios("https://pokeapi.co/api/v2/pokemon/"+response.data.chain.evolves_to[0].evolves_to[0].species.name))
setPokemonSecondFormIcon(data3.data.sprites.other.dream_world.front_default)
const data4 = await axios(data.evolution_chain.url).then((response) => axios("https://pokeapi.co/api/v2/pokemon/"+response.data.chain.species.name))
setPokemonFirstFormIcon(data4.data.sprites.other.dream_world.front_default)
}
fetchPokemonSpecies()
},[])
useEffect(()=>{
const fetchPokemonEvoChain = async (pokemon) => {
const data = await axios("https://pokeapi.co/api/v2/pokemon-species/"+pokeName).then( (response) =>
axios(response.data.evolution_chain.url)).then((response) => {setPokemonFirstEvolution(response.data.chain.evolves_to[0].species.name)
setPokemonFirstForm(response.data.chain.species.name)
setPokemonSecondEvolution(response.data.chain.evolves_to[0].evolves_to[0].species.name)})
}
fetchPokemonEvoChain()
},[])
idk if it is the optimal way but it works

useState isn't updating

I'm fetching an api and want to change useState when the api is returned. However, it simply isn't updating.
Any suggestions?
const fictionApi = "http://localhost:3000/fiction"
const nonFictionApi = "http://localhost:3000/non_fiction"
const [fictionData, setFictionData] = useState(null)
const db = async (url) => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
console.log(data.genre)
}
useEffect(() => {
const db = async (url) => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
console.log(fictionData)
}
db(fictionApi)
}, [])
I think there is something strange with your syntax.
Something like this should work :
const fictionApi = "http://localhost:3000/fiction"
const nonFictionApi = "http://localhost:3000/non_fiction"
export default function Page () {
const [fictionData, setFictionData] = useState(null);
const [url, setUrl] = useState(fictionApi); // ';' very important
useEffect(() => {
(async () => {
const res = await fetch(url)
const data = await res.json()
setFictionData(data)
})() //Self calling async function
}, [])
}
Moreover, setState is an async process so :
const [fictionData, setFictionData] = useState(null);
setFictionData(true)
console.log(fictionData) //null
So you can use a useEffect to check state :
const [fictionData, setFictionData] = useState(null);
useEffect(()=>{
console.log(fictionData) //true
},[fictionData])
setFictionData(true)

Infinite loop after adding a dependency

When I'm adding dependency fetchData, my app becomes an infinite loop.
What am I doing wrong?
React Hook useEffect has a missing dependency: 'fetchData'. Either include it or remove the dependency array
const [films, setFilms] = useState([]);
const [page, setPage] = useState(1);
const [isLoad, setIsLoad] = useState(false);
const incrementPage = () => {
setPage(page + 1);
};
const fetchData = async () => {
setIsLoad(true);
const response = await fetch(
`${baseURL}movie/popular?api_key=${API_KEY}&language=en-US&page=${page}`
).then((res) => res.json());
setFilms([...films, ...response.results]);
setIsLoad(false);
incrementPage();
};
useEffect(() => {
fetchData();
}, []);
I would place the contents of fetchData into the useEffect instead.
const [films, setFilms] = useState([]);
const [page, setPage] = useState(1);
const [isLoad, setIsLoad] = useState(false);
const incrementPage = () => {
setPage(page + 1);
};
useEffect(() => {
setIsLoad(true);
const response = await fetch(
`${baseURL}movie/popular?api_key=${API_KEY}&language=en-US&page=${page}`
).then((res) => res.json());
setFilms([...films, ...response.results]);
setIsLoad(false);
incrementPage();
}, [setIsLoad, page, setFilms, setIsLoad, incrementPage]);
Then it will automatically fetch new data if 'page' is changed.

How to combine multiple API requests in one function with fetch() in React

I have to functions getDataOne and getDataTwo. How do I combine below into one function, using fetch(), useState and useEffect?
const MyComponent = () => {
const [loading, setLoading] = useState(false);
const [dataOne, setDataOne] = useState<Data[]>([]);
const [dataTwo, setDataTwo] = useState<Data[]>([]);
const getDataOne = async () => {
setLoading(true);
const result = await fetch(
"https://my-api-link-one"
);
const jsonResult = await result.json();
setLoading(false);
setDataOne(jsonResult);
};
const getDataTwo = async () => {
setLoading(true);
const result = await fetch(
"https://my-api-link-two"
);
const jsonResult = await result.json();
setLoading(false);
setDataTwo(jsonResult);
};
useEffect(() => {
getDataOne();
getDataTwo();
}, []);
Update:
I set it up using Promise.all
const [loading, setLoading] = useState(false);
const [dataOne, setDataOne] = useState<DataOne[]>([]);
const [dataTwo, setDataTwo] = useState<DataTwo[]>([]);
const [data, setData] = useState<DataOne[] & DataTwo>([]);
const urls = [
"https://url-one", "https://url-two",
];
const getData = async () => {
setLoading(true);
const results = await Promise.all(
urls.map((url) => fetch(url).then((res) => res.json()))
);
setLoading(false);
setData(results);
console.log(data);
};
This is not totally working yet. How do I use useState now correctly (and handle both data from urls)? In the end I want to have one data variable so I can map over this variable:
{data.map((item) => {
return (
// etc
So, Promise.all() accepts an array of promises, so naturally Promise.all() returns an array only. So even though your results variable still is an array I would recommend destructuring it because in this case there are only two API fetches involved. Looking at your update, I think there's only small modifications left which are as follows :
const urls = ["https://url-one", "https://url-two",];
const getData = async () => {
setLoading(true);
const [result1, result2] = await Promise.all(
urls.map((url) => fetch(url).then((res) => res.json()))
);
setLoading(false);
setDataOne(result1);
setDataTwo(result2);
console.log(data);
};
You can use Promise.all. Read more here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all.
const getData = () => {
setLoading(true);
Promise.all([fetch('api-1'), fetch('api-2')]).then(results => {
setDataOne(results[0]);
setDataTwo(results[1]);
}).finally(() => setLoading(false));
}
Utilize .flat() to reformat the data array returned from the Promise.all() into your state which holds the response obj/array,
Promise.all(
urls.map(url =>
fetch(url).then(e => e.json())
)
).then(data => {
finalResultState = data.flat();
});

How to call custom hook inside of form submit button?

I am create custom hook that fetch requests network.I want to call custom hook when form submit button clicked but depending on hook rules i can't do that. how to can implement this scenario?
this custom hook:
const useRequest = (url, method, dependencies, data = null) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
try {
const res = await request[method](url, data);
setResponse(res);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
};
fetchData();
}, dependencies);
return { response, error, loading };
};
Move fetchData function out of useEffect and export it:
const useRequest = (url, method, dependencies, data = null) => {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
const [loading, setLoading] = useState(false);
const fetchData = async () => {
setLoading(true);
try {
const res = await request[method](url, data);
setResponse(res);
setLoading(false);
} catch (e) {
setError(e);
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, dependencies);
return { response, error, loading, fetchData };
};
Than when you can call it anywhere in your code.

Resources