How to correctly write lambda expression in fetch - reactjs

I have simple fetch in my react.js project:
export function getUserById(id) {
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/json','Access-Control-Allow-Origin':'http://localhost:9000' },
mode: 'no-cors',
};
var res = fetch("http://localhost:9000/user/"+id);//there should be a lot of strange lambdas..
return res;
}
I use this function in other file:
var user = getUserById(userStr);
//some code
//more code
var email=user.mail;
var id = user.id;
Unfortunately - res is always Promise. I don't feel functional programming and react but I need to do it. I know that there should be some lambda expression, but I have no idea how to write them. As you see I need to take email and id from returning JSON.
Thanks in advance.

You need to await the fetch call.
See this example on MDN.
export async function getUserById(id) {
const requestOptions = {
method: 'GET',
headers: { 'Content-Type': 'application/json','Access-Control-Allow-Origin':'http://localhost:9000' },
mode: 'no-cors',
};
var res = fetch("http://localhost:9000/user/"+id);//there should be a lot of strange lambdas..
return res;
}
var user = await getUserById(userStr);
//some code
//more code
var email=user.mail;
var id = user.id;
Edit: You don’t need to await the fetch call, you only need to await getUserById(userStr).

Answer is not that easy. Proper way (await returns promise!) is little bit more problematic. There is my solve ;) :
return fetch("http://your.fancy.link").then((response) => response.json())
and
function App() {
const [state, setState] = useContext(MyContext);
const [loading,setLoading] = useState(true);
const readUrlParamsFromAuthentication = () => {
var url_string = window.location.href; //window.location.href
var url = new URL(url_string);
var userStr = url.searchParams.get("user-id");
var userId = null;
var userEmail = null;
if (userStr) {
getUserById(userStr).then(user=>
{
localStorage.setItem('email', user.email);
setState({ email: user.email, isLogged: true });
console.log("TUTAAAAJ");
console.log(user.email,user.id,state.isLoggedIn);
setLoading(false);
}
);
console.log("UserStr");
}
}
useEffect(() => {
readUrlParamsFromAuthentication();
}, [])
there should be your return html ;)

Related

Adding multiple API calls to a map in reactjs using axios

I need my API call to pull NFT data from moralis and add it to a map so it can later be rendered.
This all works fine, however the limit per call on moralis is 100 lines. I have added a second API call using cursor pagination. Both API calls work individually but when I try to add both to the map it just renders the most recent one. Is there a way to show everything in the collection? Thanks in advance!!
Here is the code I currently have to call the API:
async function callApi() {
var provider = await web3Modal.connect();
web3 = new Web3(provider);
await provider.send('eth_requestAccounts');
var accounts = await web3.eth.getAccounts();
account = accounts[0];
vaultcontract = new web3.eth.Contract(VAULTABI, STAKINGCONTRACT);
let config = { 'X-API-Key': moralisapikey, 'accept': 'application/json', cursor: '' };
const nfts0 = await axios.get((moralisapi + `nft/${NFTCONTRACT}/owners?chain=polygon&format=decimal&limit=100`), { headers: config })
.then(output => {
const { result } = output.data
return result;
})
const nfts1 = await axios.get((moralisapi + `nft/${NFTCONTRACT}/owners?chain=polygon&format=decimal&limit=100`), { headers: config })
.then(output => {
const { result } = output.data
return result;
})
const nfts = (nfts0, nfts1)
const apicall = await Promise.all(nfts.map(async i => {
let item = {
tokenId: i.token_id,
holder: i.owner_of,
wallet: account,
}
return item
}))
const stakednfts = await vaultcontract.methods.tokensOfOwner(account).call()
.then(id => {
return id;
})
const nftstk = await Promise.all(stakednfts.map(async i => {
let stkid = {
tokenId: i,
}
return stkid
}))
getNfts(apicall)
getStk(nftstk)
console.log(apicall);
setLoadingState('loaded')
}

How to download a kind of stream file in React js?

I would like to download a stream file in my project.
Indeed the response form the API is like a blob.
Here i leave my code;
id and filterBody arrives as props to my component.
Really i confused if some where there are mistakes or No?
Can any one help me to find my mistakes?
Thank you.
const fetchBlobFile = async (setBlobFile, id, filterBody) => {
try {
let response = await get(`http://localhost:4000/error/table/export?error_id=${id}`, filterBody)
setBlobFile(response?.data?.blob())
} catch (error) {
}
}
function exportXslFile ({id, filterBody}) {
const [blobFile, setBlobFile] = useState(null)
useEffect(() => {
fetchBlobFile(setBlobFile, id, filterBody)
}, [id])
const export = () => {
const url = window.URL.createObjectURL(blobFile);
window.location = url
}
return (
<button className="export" onClick={export}><ExportXslFile /> Export</button>
)
}
I solved the problem as following.
This code completely works; but only be careful to import necessary packages.
const fetchBlobFile = async (setBlobFileLoading, id, body) => {
try {
const a = document.createElement("a");
a.style.display = "none";
document.body.appendChild(a);
setBlobFileLoading(true);
var data = JSON.stringify(body);
var config = {
method: 'post',
url: `http://localhost:4000/table/export?errorCsv_id=${id}`,
headers: {
'Content-Type': 'application/json'
},
data: data
};
let response = await axios(config);
setBlobFileLoading(false)
const blobFile = new Blob([response?.data], { type: 'text/csv' });
const url = window.URL.createObjectURL(blobFile);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
} catch (error) {
}
}
function exportXslFile ({id, body}) {
const [blobFileLoading, setBlobFileLoading] = useState(false)
const export = () => {
fetchBlobFile(setBlobFileLoading, id, filterBody)
}
return (
{blobFileLoading && <div className="loading fixed"><Loader /></div>} // set up loader
<button className="export" onClick={export}>Export</button>
) //download button
}

React : waiting for a promise

i got a function that uses axios to get info from my backend as follows:
const getDoH = async () => {
const user = JSON.parse(localStorage.getItem("user"));
let config = {
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + user.accessToken,
},
params: {
username: user.username,
},
};
return await axios.get(API_URL + "get", config);
};
Now i want to save these values into a global variable on initiate so i use the initialstate hook like this:
const [initialValues, setInitialValues] = useState(() => {
const initialSwitchState = getDoH().then(
(response) => {
setInitialValues(response.data);
},
(error) => {
console.log(error);
}
);
return initialSwitchState;
});
after that i got a function that takes the values from the db and maps them onto my local variable and this function looks like this:
const setStartValues = () => {
let newValues = initialSwitchState;
let valueArray = Object.entries(newValues).map((v, index) => {
v[1] = initialValues.switchValues[index]
return v
});
newValues = Object.fromEntries(valueArray);
setValues({...newValues});
}
and i want to call this function with a final function that is another initialstate hook like this:
const [values, setValues] = useState(() => {
const initialState = setStartValues();}
but by the time it gets to the line:
v[1] = initialValues.switchValues[index]
the initialValues is still a promise. and i cant see where i have gone wrong as i have used async and wait on my initial getDoH() function.
How can i solve this (wait for the promise) before i try to use the results?
kind regards.
There are two issues here:
First, you need to await getDoH() since that's an async function.
Second, useState() is a synchronous function, so you need to do the await getDoH() inside a useEffect() before you set const [initialValues, setInitialValues] = ...
Tbh i did it with use effect and it comes with its own set of issues. found the best way to do it was:
const [values, setValues] = useState(async () => {
const initialState = await getDoH().then(
(response) => {
let newValues = switchState;
let valueArray = Object.entries(newValues).map((v, index) => {
v[1] = response.data.switchValues[index]
return v
});
newValues = Object.fromEntries(valueArray);
setValues({...newValues});
},
(error) => {
console.log(error);
}
);
return initialState;
});

Why an infinite loop begins if I try to update my state with API response data?

I'm a little bit unexperienced with promises and asynchronous code and I'm building my first project with API calls.
My situation is this: I have to call Spotify API first time to get an auth token and then call it again to fetch my data with this token.
This is my code:
const FeaturedAlbums = () => {
const [featuredAlbums, setFeaturedAlbums] = useState([]);
const getToken = async () => {
const params = new URLSearchParams();
params.append("grant_type", "client_credentials");
const res = await axios({
method: "post",
url: "https://accounts.spotify.com/api/token",
headers: {
Authorization: `Basic ${process.env.REACT_APP_ENCODED_KEY}`,
},
data: params,
});
const accessToken = res.data.access_token;
return accessToken;
};
const getFeaturedAlbums = async (token) => {
const res = await axios({
method: "get",
url: "https://api.spotify.com/v1/browse/new-releases",
headers: {
Authorization: `Bearer ${token}`,
},
params: {
limit: 6,
},
});
const albums = res.data.albums.items;
// console.log(albums);
const myAlbums = albums.map((album) => ({
artist: album.artists[0].name,
img: album.images[1].url,
title: album.name,
}));
console.log(myAlbums);
return myAlbums;
};
useEffect(async () => {
const myToken = await getToken();
console.log(myToken);
const newAlbums = await getFeaturedAlbums(myToken);
setFeaturedAlbums(newAlbums);
});
I'm doing something very wrong with promises for sure but I need some hints.
Thanks a lot!!!
First, your useEffect has no dependencies, and I believe that's what causing the infinite loop. As stated in the official docs, a useEffect hook will run after the first render and after every update. Try passing an empty array [] as the second parameter of the hook, and your hook will be run once, after the first render.
useEffect(() => {
// your code here
}, []) // <-- empty array
Also, that's not how you should use async within a hook. You should define your async function in the hook, and call it right after, like so:
useEffect(() => {
async function myAsyncFunc() {
// do all the async job here
}
myAsyncFunc();
}, []);

What do I put in my return if I want to return the response from an api call react?

I needed to add headers to my api call. I tried doing this many different ways to no avail. This is my original api call without the header:
export default async function FetchPageMarkdown(page: string): Promise<string> {
const baseUrl = getBackendUrl();
let response = await fetch(`${baseUrl}/api/pagemarkdown/${page}`);
let text = await response.text();
return text
}
This is how I am trying to add the header:
const FetchPageMarkdown = (page: string): Promise<string> => {
const { getAccessTokenSilently } = useAuth0();
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
};
export default FetchPageMarkdown;
Without having a return I get a function whose declared type is neither 'void' nore 'any' must return a value. I want to return the text coming from the api call which is markdown. If I put the return outside the callSecureApi function it cannot find text.
Have you tried calling and returning the result of the asynchronous function, i.e. return callSecureApi();?
Since useAuth0 is a React hook it can't be called from functions (breaks rules of hooks), but its getAccessTokenSilently function can be passed around.
const fetchPageMarkdown = (getAccessTokenSilently: () => string, page: string): Promise<string> => {
const callSecureApi = async () => {
const token = await getAccessTokenSilently();
const baseUrl = getBackendUrl();
const response = await fetch(
`${baseUrl}/api/pagemarkdown/${page}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
}
);
const text = await response.text();
return text;
}
return callSecureApi(); // invoke and return Promise
};
Usage:
const { getAccessTokenSilently } = useAuth0();
fetchPageMarkdown(getAccessTokenSilently, page)
.then(text => {
// handle returned text
});

Resources