Avoid duplication in fetch call - reactjs

I'm trying to avoid duplication of data using fetch.
The fetch call looks like this:
const [data, setData] = useState(null);
useEffect(() => {
const promises = urls.map((url) =>
fetch(baseUrl + url).then((response) => {
if (response.ok) return response.json();
throw response
})
);
Promise.all(promises)
.then((json) => setData(json))
}, []);
return { data}
};
export default useFetchAll;
How can the fetch call be modified to avoid duplication ?
Thank you!

Look into SWR or React Query. Both of those libraries will give you a ton of features, including caching data.

Related

Using a POST request's response values in React Native

everyone. I'm a new developer and this is my first post here, so please bear with me.
What I'm trying to do is access the values that I received from a POST request that I made.
Below you can see what I'm trying to do. I set up a state where I'll store my data and then there's a function called fetchData that does a POST request and receives an object with the values, right?
Now I that I've received my object, I want to store its values in some of my variables.
Since the values have been stored in the 'data' state, I thought I would access its values by doing something like 'userName = data.userName', or something like 'age = data.userAge'. Obviously that didn't work out because my IDE does not know those values yet lol. So how do you think I should access them?
const [data, setData] = useState([{}]);
useEffect(() => {
fetchData({
ids: [0],
})
.then((response: any) => {
setData(response);
})
.catch((error: any) => {
console.log('error', error);
});
}, []);
dont place the function directly in useEffect, do something like this instead
const [data, setData] = useState([])
const getData = async() => {
try{
const response = await fetchData({ids: [0]});
setData(response);
}catch(error){
console.log(error);
}
}
useEffect(() => {
getData();
},[])

Multiple API Calls with Promise.all

I'm trying to get different data from different APIs. I don't have any problem when getting one and updating state. But I can't figure out how can I update two different state with Promise.all()
How can I make this code work.
const [stats, setStats] = useState(null);
const [info, setInfo] = useState(null);
React.useEffect(()=>{
Promise.all([
fetch('https://api.opensea.io/api/v1/collection/nickelodeon-rugrats-heyarnold-eth/stats'),
fetch('https://api.opensea.io/api/v1/asset_contract/0x223E16c52436CAb2cA9FE37087C79986a288FFFA')])
.then(res =>Promise.all(res.map(r=> r.json())))
.then((stats) => {
setStats(stats);
})
.then((info) => {
setInfo(info);
})
.then(data => console.log(data)).catch(error => console.log(error));
},[])
The Promise.alls are resolving to an array of resolve values, so the later .thens should use that array - the two URLs being fetched doesn't result in two separate .thens, it only results in a single Promise that you need to extract two properties out of.
You can also make the code simpler and DRYer by starting with an array of the two URLs and mapping over them.
React.useEffect(() => {
const urls = ['https://api.opensea.io/api/v1/collection/nickelodeon-rugrats-heyarnold-eth/stats', 'https://api.opensea.io/api/v1/asset_contract/0x223E16c52436CAb2cA9FE37087C79986a288FFFA'];
Promise.all(urls.map(url => fetch(url).then(r => r.json())))
.then(([stats, info]) => {
setStats(stats);
setInfo(info);
})
.catch(error => console.log(error));
}, []);

useEffect re-render the same result from a supabase query

I'm working with a user's bookmarks list. So, when I tried to render it doing the queries inside useEffect, it renders the result each time.
const [posts, setPosts] = useState([])
useEffect(() => {
async function getBookmarks() {
await supabase
.from('bookmarks')
.select('post_id')
.match({ user_id: user.id })
.then(res => {
res.data.map(async (bk) => {
await supabase
.from('post')
.select('id,description,songlink,created_at,author,profiles:author(username)')
.match({ id: bk.post_id })
.single()
.then(res => setPosts(posts => [...posts, res.data]))
})
})
}
getBookmarks()
}, [])
I don't want to get the same result twice or more, but I don't know what I'm doing wrong.
it might be helpful to get a better understanding of what you're wanting it to do vs what it's actually doing for people to help answer this better. What I'm seeing here in the code is you asking for data and then asking again. Knowing the data structure of your tables could help, and I'm not sure that you need to be doing multiple fetch calls here.
https://supabase.com/docs/reference/javascript/select
if your tables are joined, you should be able to just do something like
.from('bookmarks').select(`post_id:post_id ( id, description, songlink, created_at )
You might want to use useCallback hook. Didn't try the code but you can get the idea:
const [posts, setPosts] = useState([])
const getBookmarks = useCallback(async ()=>{
await supabase
.from('bookmarks')
.select('post_id')
.match({ user_id: user.id })
.then(res => {
res.data.map(async (bk) => {
await supabase
.from('post')
.select('id,description,songlink,created_at,author,profiles:author(username)')
.match({ id: bk.post_id })
.single()
.then(res => setPosts(posts => [...posts, res.data]))
})
})
},[])
useEffect(() => {
getBookmarks()
}, [])

Infinite Loop on API GET Requests

I'm relatively new to working with APIs and I'm looking to fetch data from an API using a GET request and this code is causing an infinite loop of GET requests. What I'm ultimately looking to accomplish is to access the data I'm receiving in res.data so I can pull information from the object that's being returned in the API response (using something like res.data.name which is currently prompting an error saying res is not defined which I believe could be due to a scope issue).
const Podcast=()=>{
const[show,setShow]=useState([])
const[bestPodcasts,setBestPodcasts]=useState([])
const [genre,setGenre]=useState('')
const[data,setData]=useState({})
client.fetchBestPodcasts(
{ genre_id: '91',
page: 2,
region: 'us',
safe_mode: 0,}
)
.then((res) => {
setData(res.data)
// Get response json data here
console.log(res.data);
}).catch((error) => {
console.log(error)
})
You can make use of useEffect hook, this shall call your API only once/initially:
const Podcast = () => {
const [show, setShow] = useState([])
const [bestPodcasts, setBestPodcasts] = useState([])
const [genre, setGenre] = useState('')
const [data, setData] = useState({})
useEffect(() => {
apiCall()
}, []);
const apiCall = () => {
const data = {
genre_id: '91',
page: 2,
region: 'us',
safe_mode: 0
}
client.fetchBestPodcasts(data)
.then(res => setData(res.data))
.catch(error => console.log(error))
}
}

useEffect not triggering but the template is being rendered somehow

I am getting too many re-renders while using react-hooks.
I am trying to fetch data from api by using a parameter in URL.
Here's the code:
export default function Details() {
const { title } = useParams();
const [loading, setLoading] = useState(true);
const [details, setDetails] = useState([]);
const [error, setError] = useState("");
function getDetails(keyword) {
if (keyword) {
setLoading(true);
fetch(
`API`
)
.then((res) => {
let result = res.data.results;
result = result.filter(function (result) {
return (result.title = keyword);
});
setDetails(result[0]);
setLoading(false);
console.log(details);
})
.catch((err) => {
setError(["Unable to fetch data"]);
setLoading(false);
});
}
}
getDetails(title)
return(
// template
)
now I think this is happening at the line where I call getDetails.
then I tried using useEffect to load the data only once after it is mounted,
useEffect(() => {
getDetails(title);
}, []);
It still is unable to fetch the data, as the getDetails function is never called.
How can I resolve this?
Edit:
Fixed one silly error.
Here's the codesandbox link:
Codesandbox
There are multiple issues with this, first you need to specify what you want to be notified about when the useEffect gets called again. You could do this by adding the variables you want within the array
useEffect(() => {
getDetails(title);
}, [
// Add what you want here
]);
The second issue you have is that you declared the detalis variable twice. Once using the set state here: const [details, setDetails] = useState([]);
The second time here:
const details = getDetails(title)
the code here has two obvious error beside the functionality problems you mentioned:
1 - you cannot declare two variables with same name using let or const; it will throw a SyntaxError
const [details, setDetails] = useState([]);
...
const details = getDetails(title)
2- getDetails function is written with a asynchronous mindset, and it will return nothing,
so details in const details = getDetails(title) will be set to undefined
Looks like your getDetails function has title param so I would add title and getDetails both in the dependency list of useEffects
Or place getDetails inside the useEffect
Here is your working code. You had multiple problems where res.data was undefined so you need to get res.results directly based on your response object
useEffect(() => {
function getDetails(keyword) {
if (keyword) {
setLoading(true);
fetch(
`https://api.jikan.moe/v3/search/anime?q=${keyword}&page=1&genre_exclude=0`
)
.then((res) => res.json())
.then((res) => {
console.log(res.results);
let result = res.results;
console.log(result);
result = result.filter(function (result) {
return (result.title = keyword);
});
setDetails(result[0]);
setLoading(false);
console.log(3);
})
.catch((err) => {
console.log(err);
setError(["Unable to fetch data"]);
setLoading(false);
});
}
}
console.log('calling getDetails')
getDetails(title);
}, [title]);
Note: tested in the code sandbox link provided in the question. Its working code.

Resources