React state not updating correctly - reactjs

I have a usecase where I want to call an API at a regular interval until API returns a response saying not to reload further. Following is my code.
const [username, setUserName] = React.useState();
const [reloadEstimates, setReloadEstimates] = React.useState(true);
const [estimates, setEstimates] = React.useState([]);
const [progress, setProgress] = React.useState(true);
const [showError, setShowError] = React.useState(false);
const [errorMessage, setErrorMessage] = React.useState();
useEffect(() => {
const token = jwt(Cookies.get('id-token'));
const username = token["cognito:username"]
setUserName(username)
async function fetchData() {
let allestimates = await fetch(<api-url>, {
//mode: 'cors',
method: 'GET',
headers: new Headers({'Authorization' : 'Bearer ' + Cookies.get('id-token')})
})
.then(res => {
if(res.ok) {
return res.json();
}
throw new Error(`API call failed: ${res.code} - ${res.message}`);
})
.catch(er => { setShowError(true); setErrorMessage(`API error: ${er}`); } );
//console.log(allestimates)
return allestimates;
}
async function refreshEstimate() {
console.log("checkpoint1");
console.log(reloadEstimates);
if (reloadEstimates === true){
fetchData().then(
allelatimates =>{
setEstimates(allelatimates.estimates);
console.log(allelatimates )
console.log(allelatimates.reload )
if(allelatimates.reload === 'NOT RELOAD'){
console.log("checkpoint2");
return false;
}
return true;
}
).then((r)=>{console.log(r);setReloadEstimates(r); console.log(reloadEstimates)}).then(()=>setProgress(false));
}
else{
console.log('No need to fetch.')
}
}
var refreshInterval = setInterval(() => {
refreshEstimate();
}, 10000);
},[]);
I don't know why but setReloadEstimates(r) does not convert state reloadEstimates to false. And it keeps on running. Following is the console output. Please let me know what i am missing or is there another way to achieve this. Thanks.
enter image description here

Related

Object (promise.all) to useState

I am trying to set an object to useSate.
The object is the dataMap which should be passed to the setResults
Any help would be appreciated ?
export default function Home() {
const [results, setResults] = useState([]);
const fetchResults = async () => {
const res = await fetch(
'someurl'
);
const data = await res.json();
const dataMap = data.reduce((acc, curr) => {
return {
...acc,
[curr.id]: curr
};
}, {});
const requests = Object.keys(dataMap).map(async (productId) => {
const request = await fetch(
`someUrl/${productId}`
);
const response = await request.json();
return response;
});
const responseAll = await Promise.all(requests);
responseAll.forEach(
({ id, color }) => (dataMap[id] = { ...dataMap[id], color })
);
//console.log(dataMap);
setResults(dataMap)
};
const requests = Object.keys(dataMap).map(async (productId) => {
const request = await fetch(
`someUrl/${productId}`
);
const response = await request.json();
return response;
});
This piece of code will trigger all the api's till the end of Object.keys(dataMap)
To update the state with the values.
You need to update the state just after await like this:
const requests = Object.keys(dataMap).map(async (productId) => {
const request = await fetch(
`someUrl/${productId}`
);
const response = await request.json();
setResults(prev=>[...prev,response])
});

I want my axios query 1 is finish to execute my 2nd

I would like my "userid" to no longer be null for executing my 2nd request. the code is
const [userid, setUserid] = useState(null)
const userConnected = useEffect(() => {
(async () => {
try {
const resp = await httpClient.get("//localhost:5000/#me");
setUserid(resp.data.id)
console.log(resp.data.id)
} catch (error) {
console.log("Not authenticated");
}
})();
}, []);
const fetchUserItem = async () => {
try {
const owner = await axios({
url: `${baseUrl}/additem/owner/${userid}`, //problem:
//user.id = Null
//so its like ${baseUrl}/additem/owner/null
method: 'get'
})
const { events } = owner.data
console.log(owner.data)
setitemList(events)
}
catch {
console.log('error')
}
}
i think the problem is:
as the 2 requests are carried out at the same time the {userid} = null (usestate)
so I have http://5000/additem/owner/null
i must have http://5000/additem/owner/12423
Try it, maybe this would work out:
const [userid, setUserid] = useState(null);
const userConnected = useEffect(() => {
// to run below function only when userid is null
userid == null
? (async () => {
try {
const resp = await httpClient.get("//localhost:5000/#me");
setUserid(resp.data.id);
console.log(resp.data.id);
} catch (error) {
console.log("Not authenticated");
}
})()
// call fetchUserItem inside useEffect
: (async () => {
await fetchUserItem();
})();
}, [userid] /* define userid in dependency array */);

how to refactor duplicate API calls into a single API call?

I am pretty new to building full-stack applications, and I could like to avoid duplicating code in order to build the following to perform the calls in react my endpoints can be called like the following /api/v1/feeds/list/?page=${page} or api/v1/feeds/list/?search=${query} , but I would like to joing ?page=${page}&?search=${query} since search param is optional . I just want to make a single api call
async function fetchFeed(page) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?page=${page}`);
}
async function searchQuery(query) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?search=${query}`);
}
const Main = () => {
const [currentPage, setCurrentPage] = useState(1);
const [feed, setFeed] = useState([]);
const [feedCount, setfeedCount] = useState(0);
const [visible, setVisible] = useState(3)
const showMoreItems = () => {
setVisible(prevValue => prevValue + 3);
}
const browse = (page) => {
fetchFeed(page)
.then(function(response){
setfeedCount(response.data.count)
setFeed(response.data.results)
})
.catch(function(error){
console.log(error);
});
}
// fetches data
const fetchData = (search) => {
searchQuery(search)
.then((response) => {
setFeed(response.data.results)
})
.catch((error) => {
console.log(error);
});
};
const handleSearch = (e) =>{
fetchData(e.target.value);
}
useEffect(() => {
browse(currentPage)
fetchData(feed);
}, [currentPage]);
}
I'd pass an object with both page and query, which both default to the empty string - and if empty, don't include them in the fetched URL:
async function fetchFeed({ page = '', query = '' }) {
return api.get(`http://localhost:8001/api/v1/feeds/list/?${page ? `page=${page}&` : ''}${query ? `search=${query}` : ''}`);
}
If possible, make your API accept empty query parameters too, allowing you to simplify to
return api.get(`http://localhost:8001/api/v1/feeds/list/?page=${page}&query=${query}`);
Something like this should work for you
const fetchFeed = async (page, query) => {
let url =`http://localhost:8001/api/v1/feeds/list/?page=${page}`
if(query) url += `?search=${query}`
return api.get(url)
}
const browse = (page search) => {
await fetchFeed(page search)
.then(function(response){
!search && setfeedCount(response.data.count)
setFeed(response.data.results)
})
.catch(function(error){
console.log(error);
});
}
useEffect(() => {
browse(currentPage) // just pass page
browse(currentPage, searchQuery); // pass both page and search query
}, [currentPage]);

How to get URL from firebase storage?

I have the following code:
const imgURL = () => {
const fileName = report.reporter.avatar.Pc.path.segments[8];
const storageRef = storage.ref('images');
storageRef.child(`/${fileName}`).getDownloadURL().then((url) => {
console.log(url) // here I am getting the url in the console
return url;
});
}
console.log(imgURL()); // here its undefiend
for some how I dont know why I cant get what the function return
You can try something like this with async / await i don't know if async / await works for react.
const imgURL = async () => {
const fileName = report.reporter.avatar.Pc.path.segments[8];
const storageRef = storage.ref('images');
const url = await storageRef.child(`/${fileName}`).getDownloadURL().catch((error) => { throw error });;
return url;
}
change your calling method with this :
console.log(await imgURL());
that what fixed my code (useState)
const [avatarUrl, setAvatarUrl] = useState('');
const imgURL = async () => {
const fileName = report.reporter.avatar.Pc.path.segments[8];
const storageRef = storage.ref('images');
await storageRef.child(`/${fileName}`).getDownloadURL().then((url) => {
setAvatarUrl(url);
});
}
imgURL();

http fetch returns true instead of actual data

I am trying to use a http hook in another component to send a get request. The post request is working fine. But when I try a get request I just get back 'true' when I console log my result. When I send the same get request in postman I get the correct data back, so it isn't a backend problem.
The hook:
import { useState, useCallback, useRef, useEffect } from "react";
export const useHttpClient = () => {
const [isLoading, setIsLoading] = useState(false);
const [errors, setErrors] = useState();
const [success, setSuccess] = useState(false);
const activeHttpRequests = useRef([]);
const sendRequest = useCallback(
async (url, method = "GET", body = null, headers = {}) => {
setIsLoading(true);
const httpAbortController = new AbortController();
activeHttpRequests.current.push(httpAbortController);
try {
setErrors();
setSuccess(false);
const response = await fetch(url, {
method: method,
body: body,
headers: headers,
signal: httpAbortController.signal,
});
const responseData = await response.json();
activeHttpRequests.current = activeHttpRequests.current.filter(
(reqCtrl) => reqCtrl !== httpAbortController
);
if (response.status !== 200) {
setErrors(responseData);
return responseData;
} else {
setSuccess(true);
return true;
}
} catch (err) {
//setErrors(err.message);
setErrors([
"There was an error submitting your form, please try again later.",
]);
setIsLoading(false);
throw err;
}
},
[]
);
//useEffect can also be used for cleanup
useEffect(() => {
return () => {
activeHttpRequests.current.forEach((AbortController) =>
AbortController.abort()
);
};
}, []);
return { isLoading, errors, sendRequest, success };
};
The server call:
useEffect(() => {
const fetchFaq = async () => {
try {
const responseData = await sendRequest(
"http://localhost:8000/api/myEndpoint"
);
console.log(responseData);
setLoadedFaq(responseData);
} catch (err) {}
};
fetchFaq();
}, [sendRequest]);
Your hook returns true if it gets a 200 response code:
if (response.status !== 200) {
setErrors(responseData);
return responseData;
} else {
setSuccess(true);
return true;
}
It only returns responseData if it gets a non-200 code. Just return the data from the hook..

Resources