I'm trying to do an API call using fetch().
I'm aware that fetch() returns a Promise and should be handled using .then or await. The same for the result.json() Followed this tutorial http://www.reactnativeexpress.com/networking, I arrived with fetchRoute()function. The console.log(route) inside the function is never called.
I tried to return console.log(fetchRoute(this.state.userLocation, text)), but it was still returning a Promise.
I read another quesiton here on Stack Overflow (sorry, can't find the link anymore), and they said to try something like this:
getRouteHandler = (text) => {
fetchRoute(this.state.userLocation, text).then(json => console.log(json));
Still, I couldn't log the fetch results. Anyone knows what could be going wrong? Here is the relevant code:
const fetchRoute = async (ori, dest) => {
let origin = ori.latitude+','+ori.longitude;
let destination = encodeURIComponent(dest);
const key = "MyAPIKey";
const URL = `https://maps.googleapis.com/maps/api/directions/json?origin=${origin}&destination=${destination}&key=${key}`;
try{
const response = await fetch(URL)
const route = await response.json()
console.log(route)
return route
}catch(e){
return e
}
}
export default class App extends Component{
state = {
userLocation: null,
route: [],
}
getRouteHandler = (text) => {
fetchRoute(this.state.userLocation, text).then(json => console.log(json));
}
Sometimes if you're fetching large amounts of data it will take awhile for it to log. For example, in a past project the api I was fetching from had close to 5 million records. It took a few minutes to see anything in the console.
Related
I have an API called getQuote and a component called QuoteCard. Inside QuoteCard I'm trying to render an array of users that liked a quote. The API works fine, I have tested it, and the code below for getting the users works fine too.
const Post = async (url, body) => {
let res = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"accept": "*/*"
},
body: JSON.stringify(body)
}).then(r => r.json());
return res;
}
const getAllLikes = async () => {
let users = await Post('api/getQuote', {
id: "639e3aff914d4c4f65418a1b"
})
return users
}
console.log(getAllLikes())
The result is working as expected :
However, when trying to map this promise result array to render it onto the page is where I have problems. I try to render like this:
<div>
{getAllLikes().map((user) => (
<p>{user}</p>
))}
</div>
However, I get an error that states:
getAllLikes(...).map is not a function
I don't understand why this is happening. Why can't I map the array? Is it because it's a promise or something?
And if anyone needs to see the getQuote API, here it is:
//Look ma I wrote an API by myself! :D
import clientPromise from "../../lib/mongodb";
const ObjectId = require('mongodb').ObjectId;
import nc from "next-connect";
const app = nc()
app.post(async function getQuote(req, res) {
const client = await clientPromise;
const db = client.db("the-quotes-place");
try {
let quote = await db.collection('quotes').findOne({
_id: new ObjectId(req.body.id)
})
res.status(200).json(JSON.parse(JSON.stringify(quote.likes.by)));
} catch (e) {
res.status(500).json({
message: "Error getting quote",
success: false
})
console.error(e);
}
})
export default app
Thanks for any help!
It is due to the fact that getAllLikes is an async function and thus it returns promise which does not have a map function.
You can either save it in a state variable before using await Or chain it with .then.
Minimal reproducible example which works
const getAllLikes = async () => {
return ['a', 'b']
}
getAllLikes().then((r) => r.map((g) => { console.log(g) }))
Edit: The above code won't work if directly used with jsx since the return of getAllLikes will still be a promise. Solution would be to save it in a state variable and then using it.
I am from Angular and I believe we call pipe on Observables (or Promises). Map can then be called inside the pipe function
observable$ = getAllLikes().pipe(map( user => <p>{user}</p>))
If there is no pipe, I can only think of manually subscribing (which is not a good practice)
sub$ = getAllLikes().subscribe( user => <p>{user}</p>)
// unsub from sub$ appropriately
// We do this from ngOnDestroy in angular
ngOnDestroy() {
this.sub$?.unsubscribe()
}
This question already has an answer here:
Fetch error when building Next.js static website in production
(1 answer)
Closed 6 months ago.
I'm getting the below error using getStaticProps(). What's the problem here? Using nextjs and I'm passing the returned value as props to a component. I have no idea what's happening here and have tried several things (await, JSON.stringify()) but nothing is working. When I run the api route separately it works so I know the api route is good. Also when I use the names constant it works as well.
export async function getStaticProps(){
//const names = {fname: "jim", age: "bob", grade: 10}
const res = axios.get("/api/teacher/loadstudents")
.then(res=>{
console.log(res.data);
})
.catch(err => {console.log(err)})
const studentdata = JSON.stringify(res.data);
return {
props:{data: studentdata}
}
}
const TeacherMainPage = (props)=>{
var classCode = "XZLE123";
console.log("These are the props: ", props) ;
The issue is that your code execution is not happening top to bottom as you think, axios.get is an async call, so then executed asynchronously, but JSON.stringyfy executes synchronously.
To correct it, you can put await before axios.get to wait for the promise to resolve then execute JSON.stringify followed by return. It is also a good idea to use try catch here if going await route.
export async function getStaticProps(){
try {
const res = await axios.get("/api/teacher/loadstudents");
const studentdata = JSON.stringify(res.data);
return {
props:{ data: studentdata }
}
} catch(error) {
console.log(error)
return {};
}
}
One thing to note though, probably JSON.stringify is not needed here.
I'm in react Native, and I have a request that im making using axios, and the request is supposed to return something like this:
Json data
I want to be able to save only the "Products" array in a variable.
This is the snippet of my cod, but it's giving me a 'Possible unhandled promise rejection' and I dont understand why:
const [shoesData, setShoesData] = useState([]);
useEffect(() => {
const getShoesData = async () => {
await axios.get("https://stockx.com/api/browse?productCategory=sneakers&sort=release_date&releaseTime=gte-" + Date.now().toLocaleString() + "&order=ASC&country=FR")
.then(response => {
let products = response.data.map(x => {
return x.products;
});
setShoesData(products);
console.log(products);
})
}
getShoesData();
}, [])
Thanks in advance for your help.
Try and wrap your await instruction with a try catch. One possible error can be that the data you get from the response can, in some cases, not have a products field.
I'm developing the front-end for my spring boot application. I set up an initial call wrapped in a useEffect() React.js function:
useEffect(() => {
const getData = async () => {
try {
const { data } = await fetchContext.authAxios.get(
'/myapi/' + auth.authState.id
);
setData(data);
} catch (err) {
console.log(err);
}
};
getData();
}, [fetchContext]);
The data returned isn't comprehensive, and needs further call to retrieve other piece of information, for example this initial call return an employee id, but if I want to retrieve his name and display it I need a sub-sequential call, and here I'm experiencing tons of issues:
const getEmployeeName = async id => {
try {
const name = await fetchContext.authAxios.get(
'/employeeName/' + id
);
console.log((name["data"])); // <= Correctly display the name
return name["data"]; // return an [Object promise],
} catch (err) {
console.log(err);
}
};
I tried to wrap the return call inside a Promise.resolve() function, but didn't solve the problem. Upon reading to similar questions here on stackoverflow, most of the answers suggested to create a callback function or use the await keyword (as I've done), but unfortunately didn't solve the issue. I admit that this may not be the most elegant way to do it, as I'm still learning JS/React I'm open to suggestions on how to improve the api calls.
var output = Object.values(data).map((index) =>
<Appointment
key={index["storeID"].toString()}
// other irrelevant props
employee={name}
approved={index["approved"]}
/>);
return output;
Async functions always return promises. Any code that needs to interact with the value needs to either call .then on the promise, or be in an async function and await the promise.
In your case, you should just need to move your code into the existing useEffect, and setState when you're done. I'm assuming that the employeeID is part of the data returned by the first fetch:
const [name, setName] = useState('');
useEffect(() => {
const getData = async () => {
try {
const { data } = await fetchContext.authAxios.get(
"/myapi/" + auth.authState.id
);
setData(data);
const name = await fetchContext.authAxios.get(
'/employeeName/' + data.employeeID
);
setName(name.data);
} catch (err) {
console.log(err);
}
};
getData();
}, [fetchContext]);
// ...
var output = Object.values(appointmentsData).map((index) =>
<Appointment
key={index["storeID"].toString()}
// other irrelevant props
employee={name}
approved={index["approved"]}
/>);
return output;
Note that the above code will do a rerender once it has the data (but no name), and another later when you have the name. If you want to wait until both fetches are complete, simply move the setData(data) down next to the setName
I am trying to get data from server via axios.post().
Decided to use POST and not GET because I want to send an array with ids to look up in the database, which might be too large to fit in GET query params.
I managed to send an array with ids in the body of the POST. This reaches my server. I can successfully find the items in the data base. The items are then returned in the response. The data shows up in Chrome devtools > Network (status 200). I also get the right stuff back when sending a request manually using Postman.
Everything seems to be working fine, but the response does not arrive in my data variable in the axios function.
I spent the day trying out the solutions to all the similar answers here. Nothing worked...
I also tried GET and sending the ids in query params instead, which gives the same error. I suspect I am doing something wrong with async/await because I am getting this "intermediate value" thingy.
Thanks in advance for the help.
CLIENT axios functions
const url = 'http://localhost:5000';
export const getStuff = Ids => {
axios.post(
`${url}/cart/stuff`,
{
Ids: Ids,
},
{
headers: {
'Content-Type': 'application/json',
},
}
);
};
CLIENT actions
import * as api from '../api';
export const getStuff = Ids => async dispatch => {
try {
// Ids is an array like ["5fnjknfdax", "5rknfdalfk"]
const { data } = await api.getStuff(Ids);
// this gives me the error in the title, data never comes through
//dispatch(-dolater-);
} catch (error) {
console.log(error);
}
};
SERVER controllers
export const getStuff = async (req, res) => {
try {
const { Ids } = req.body;
const stuff = await STUFF.find().where('_id').in(Ids);
console.log('SERVER', stuff);
// this works until here. request comes through and
// I can successfully find the stuff I want in the database
res.status(200).json(stuff); // this also works, response is being sent
} catch (error) {
res.status(404).json({ message: error });
}
};
SERVER routes
router.post('/cart/stuff', getStuff);
You have some extra curly braces here (or a missing return, depending on how you look at it). When you use a lambda (arrow function) with curly braces, you have to explicitly return a value or else it will return undefined. Change your code from this:
export const getStuff = Ids => {
axios.post(...);
};
to one of these:
// Option 1
export const getStuff = Ids => {
return axios.post(...);
};
// Option 2
export const getStuff = Ids => axios.post(...);
Either format will return the actual axios promise, instead of the default undefined.
export const fetchPost = () => {
return axios.get(url);
};
This works for me!!