my useFetch custom hook is giving me infinite loop - javascript

**the code below is my context which I am using useFetch **
**when i change the url with changing the searchTerm **
** i am getting an infinite loop **
import React, { useContext, useState, useEffect } from "react";
import { useFetch } from "../hooks/useFetch";
const context = React.createContext();
const AppProvider = ({ children }) => {
let url = " https://www.thecocktaildb.com/api/json/v1/1/search.php?s=";
let [searchTerm, setSearchTerm] = useState("a");
useFetch(`${url}${searchTerm}`);
setSearchTerm('s');
return <context.Provider value={"hello"}>
{children}
</context.Provider >
}
const useGlobal = () => {
return useContext(context);
}
export { AppProvider, useGlobal };
** the code below is my custom hook useFetch**
`
import { useEffect, useState } from "react";
export const useFetch = (url) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
const getData = async () => {
try {
const response = await fetch(url);
const jsonResponse = await response.json();
setData(jsonResponse);
setLoading(false);
} catch (err) {
console.log(err);
}
}
useEffect(() => {
getData();
}, [url])
return { data, loading };
}
`
I tried to change the search Term like this
searchTerm="h"
and it works perfectly but when i change searchTerm with setSearchTerm it gives me infinite loop

setSearchTerm('s'); inside a useEffect
const [url] = useState(" https://www.thecocktaildb.com/api/json/v1/1/search.php?s=");
const [searchTerm, setSearchTerm] = useState("a");
const { data, loading } = useFetch(`${url}${searchTerm}`);
useEffect(() => {
setSearchTerm('s');
}, [])

Related

How to inject a service in a api conext?

I have a api context and I have a service. And I try to write the logic in each of the components.
So I have the service:
const CategoryService = () => {
const fetchCategoryData = async () => {
try {
const response = await fetch("http://192.168.1.68:19000/animal/categories/main_groups/", {
method: "GET",
});
if (!response.ok) {
throw new Error("Network response was not ok");
}
return await response.json();
} catch (error) {
console.error("There was a problem with the fetch operation:", error);
throw error;
}
};
return fetchCategoryData;
};
export default CategoryService;
and I have the context:
import { createContext, useState } from "react";
const CategoryContext = createContext();
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};
export default CategoryContextProvier;
Question: how to communicate these two witch each other?
you can just call fetchCategoryData in CategoryContextProvier useEffect
like this
const CategoryContextProvier = (props) => {
const [categoryList, setCategoryList] = useState([]);
const [loading, setLoading] = useState(false);
const value = {
categoryList,
loading,
setCategoryList,
setLoading,
};
useEffect(()=>{
setLoading(true);
fetchCategoryData()
.then(res=> setCategoryList(res))
.finally(()=> setLoading(false));
},[])
return <CategoryContext.Provider value={value}>{props.children}</CategoryContext.Provider>;
};

What would be the best solution to avoid this infinite loop (useEffect)

I developed an application where I get an api (pokeAPI) with pokemons, and basically I have a global array with "myPokemons", so I want to display all my pokemons except the ones in that array, so I created the function "filterMyPokemons" that I filter the pokemons that should be displayed, and then I call this function in useEffect so that it is updated along with the page, putting a dependency array from the API list. The problem is that I now have an infinite loop that hurts the performance of the application.
import * as C from './styles';
import logo from '../../assets/pokelogo.png';
import { useContext, useState } from 'react';
import { useApi } from '../../hooks/useApi';
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import Pokelist from '../../components/PokeList';
import CatchingPokemonIcon from '#mui/icons-material/CatchingPokemon';
import CatchContext from '../../context/Context';
const Homepage = () => {
const api = useApi();
const { showMyPokemons } = useContext(CatchContext);
const navigate = useNavigate();
const [pokemonList, setPokemonList] = useState([]);
const [loading, setLoading] = useState(false);
const [text, setText] = useState('');
const [myPokemonsList, setMyPokemonsList] = useState([]);
const [pokemonListFiltered, setPokemonListFiltered] = useState([]);
useEffect (() => {
const getAllPokemons = async () => {
const myPokemons = await showMyPokemons();
const pokemon = await api.getAllPokemon();
setLoading(true);
setPokemonList(pokemon);
setMyPokemonsList(myPokemons);
setLoading(false);
}
filterMyPokemons();
getAllPokemons();
}, [myPokemonsList]);
const filterMyPokemons = async () => {
const filteredList = await pokemonList.filter(pokemons => !myPokemonsList.includes(pokemons.name))
return setPokemonListFiltered(filteredList);
};
const lowerSearch = text.toLocaleLowerCase();
const filteredPokemons = pokemonListFiltered.filter(pokemon => pokemon
.name.toLowerCase().includes(lowerSearch)
);
const handleHome = () => {
navigate('/')
}
const handleMyPokemons = () => {
navigate('/mypokemons')
}
return (
<C.Container>
<C.Logo>
<img src={logo} alt="" />
</C.Logo>
<C.Navbar>
<input
type="text"
placeholder='Busque um pokémon...'
onChange={(e) => setText(e.target.value)}
value={text}
/>
</C.Navbar>
<C.Pokedatabase onClick={handleMyPokemons}>
<button>Meus pokémons <i><CatchingPokemonIcon /></i></button>
</C.Pokedatabase>
<C.Pokelist>
{filteredPokemons.map(pokemon => {
return (
<Pokelist
name={pokemon.name}
/>
)
})}
</C.Pokelist>
</C.Container>
)
}
export default Homepage;
If I leave useEffect's dependency array empty, the items are not displayed, but if I leave any dependencies it causes an infinite loop. How to solve this problem?
The problem comes with updating the myPokemonsList array within the useEffect hook that depends on that array.
useEffect (() => {
const getAllPokemons = async () => {
const myPokemons = await showMyPokemons();
const pokemon = await api.getAllPokemon();
setLoading(true);
setPokemonList(pokemon);
setMyPokemonsList(myPokemons); // Here's the infinite loop
setLoading(false);
}
filterMyPokemons();
getAllPokemons();
}, [myPokemonsList]); // Here's the infinite loop
You should have another use effect for updates on the myPokemonList in order to avoid updating and depending on the same list.

I want to pull the headers in the data in the useFetch function I created

I want to pull the headers in the data in the useFetch function I created.
What can I write instead of the following function (data + title).
//const {data, loading} = useFetch(data + title);
//DetailPage
import React from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
import useFetch from '../../components/Hooks/useFetch';
import styles from './Detail.style';
const Detail = ({route}) => {
const {title} = route.params;
const {data, loading} = useFetch(data + title);
console.log(title);
if (loading) {
return <ActivityIndicator/>
}
return (
<View style={styles.container}>
<View style={styles.body_container}>
<Text style={styles.title}>{data.title}</Text>
<Text style={styles.description}>{data.description}</Text>
<Text style={styles.programType}>{data.programType}</Text>
<Text style={styles.releaseYear}>{data.releaseYear}</Text>
</View>
</View>
)
}
export default Detail;
//useFetch
import { useState, useEffect } from "react";
const useFetch = () => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response = await fetch('https://gist.githubusercontent.com/hknclk/5710c4adb791755b31ccde6777f04bd2/raw/19954b5d84f476a1d691ce43e4319292893cc27a/sample.json');
const json = await response.json();
setData(json.entries);
setLoading(false);
} catch (error) {
setLoading(false);
}
}
return {data, loading}
}
export default useFetch;
You should be able to access the headers using response.headers
So, once you have a response object, it is just a matter of accessing the iterator and storing it in a format suitable for you. (Feel free to change it)
import { useState, useEffect } from "react";
const useFetch = () => {
const [data, setData] = useState([]);
const [headers, setHeaders] = useState({})
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
try {
const response = await fetch('https://gist.githubusercontent.com/hknclk/5710c4adb791755b31ccde6777f04bd2/raw/19954b5d84f476a1d691ce43e4319292893cc27a/sample.json');
const json = await response.json();
let headers = {};
for (const kvp of response.headers.entries()) {
headers[kvp[0]] = kvp[1]
console.log(`${kvp[0]}: ${kvp[1]}`);
}
setData(json.entries);
setHeaders(headers)
setLoading(false);
} catch (error) {
setLoading(false);
}
}
return {data, headers, loading}
}
export default useFetch;

fetch dosent bring any data

when i use fetch to bring the list of notes and consol.log it nothing shows up. The url is not wrong i have carefully checked it. Here is the code:
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect(() => {
}, [])
let getNotes = async () => {
let response = await fetch('http://127.0.0.1:8000/api/notes/')
let data = await response.json()
console.log(data)
setNotes(data)
}
return (
<div>
</div>
)
}
export default NotesListPage
here is the api part:
#api_view(['GET'])
def getNotes(request):
notes = Note.objects.all()
serializer = NoteSerializer(notes, many=True)
return Response(serializer.data)
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect(() => {
getNotes();
}, [])
let getNotes = async () => {
let response = await fetch('http://127.0.0.1:8000/api/notes/')
let data = await response.json()
console.log(data)
setNotes(data)
}
return (
<div>
</div>
)
}
export default NotesListPage
You are not calling your function 'getNotes'
The way I would do it, it to fetch your data in the Effect hook and set it in your state hook there.
import React, { useState, useEffect } from 'react'
const NotesListPage = () => {
let [notes, setNotes] = useState([])
useEffect( async () => {
const response = await fetch('http://127.0.0.1:8000/api/notes/')
.then(response => response.json())
setNotes(response)
}, [])
console.log(notes)
return (
<div>
</div>
)
}
export default NotesListPage
*Edit
Cleaner would be to have the fetch in a seperate function doing the same thing and just calling that function in your effect hook (see other answer above*)

Why does this custom hook return indefined in react?

i am creating a custom hook in React, this is my code:
import {useEffect} from 'react';
const useFetch = (url) => {
useEffect(() => {
const fetchData = () => {
const data = url + "TEST";
return data;
}
fetchData();
})
}
export default useFetch;
It now returns some dummy value but that is just because of testing purposes.
Here is where i invoke my custom hook:
const Data = useFetch("https://customapiurlrandom.com/");
useEffect(() => {
console.log(Data);
}, [])
The thing is, when i check my console i see undefined. And i can't find out why.
Any ideas? Thanks in advance.
Your custom hook didn't return anything. You should add a state to keep the value and return it
import {useEffect, useState} from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = () => {
const data = url + "TEST";
return data;
}
setData(fetchData());
},[url, setData]);
return data;
}
export default useFetch;
And then use like this
const Data = useFetch("https://customapiurlrandom.com/");
useEffect(() => {
console.log(Data);
}, [Data])

Categories

Resources