fetching only in the second click - javascript

i have a problem on my fetching.
i fetched API to my project, when i trying to use display on value, it doesn't work on the first click. at the second click the function will run good and everything works.
when im trying to log in the fetching function everything works good, but, at the display function i get an error:
also if i write a number of pokemon to search and click to search it doesnt work but, if i change it and click again, i will get the first pokemon value.
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
im adding the function of the fetch and also the display function
i can also send the git reposetory if anyone want to help.
thenks
let fetetchPokemon = function (inputNum) {
fetch(`${pokemonApi}` + `${inputNum}`)
.then((response) => response.json())
// .then((response) => console.log(response))
.then(
(response) =>
(pokemon = new Pokemon(
response.name,
response.sprites,
response.moves,
response.types,
response.abilities
))
)
// .then((pokemon) => console.log(pokemon.name));
// .then((pokemon) => console.log(pokemon.name))
.then(displayPokemon());
};
let displayPokemon = function () {
pokemonName.innerText = pokemon.name;
console.log(pokemon.name);
pokemonImg.src = pokemon.image.front_default;
displayMoves(pokemon.moves);
displayType(pokemon.types);
displayAbilities(pokemon.abilities);
};
there is also a bin to see the code:
https://jsbin.com/puvotid/edit?html,css,js,output

The display method must be placed same scope with variable assignment.
So the method will look like
const fetetchPokemon = function (inputNum) {
fetch(`${pokemonApi}` + `${inputNum}`)
.then((response) => response.json())
.then(
(response) => {
pokemon = new Pokemon(
response.name,
response.sprites,
response.moves,
response.types,
response.abilities
);
displayPokemon();
}
);
};
As answer below from #Mamoud, you should use async/await or callback invidually, not both

use async and await to wait the results.
const fetchPokemon = async function(){
await fetch(...).then(...)
}

Related

data.json is not a function reactjs using Fetch API

I have delete function using fetch api but while deleting, I'm getting this error, data.json is not a function
This is my code
export const deleteLeaveType = async id => {
const response = await fetch(
`${API_LINK}/route/route/route/${id}`, {
method: 'delete',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${Auth.getToken()}`,
},
}
);
return getData(response);
};
I'm calling it in another file
const deleteLeaveType = async id => {
let deleteLeaveType = isLeaveType.filter(
item => item.id !== id
);
await CalendarManagementAPI.deleteLeaveType(id)
.then(data => {
console.log(data.json());
setLeaveType(deleteLeaveType);
});
setLoadingLeaveTypes(false);
fetchLeaveTypes();
})
.catch(error => {
console.log(error);
});
};
Main issue:
The main issue you're running into is that in your top deleteLeaveType function, you're ending with return getData(response), instead of just returning whatever you received from your fetch request.
As you can see from the docs, the normal way to use fetch is to just do const response = await fetch(...) (as you've already done), then immediately after call data.json() (which is another async function, by the way). However, your getData(response) function is probably not returning exactly what you expect.
Other comments:
As mentioned in the comments, you probably shouldn't be using async / await at the same time as .then(). These are two different ways of handling async functions, so only one should be used at a time.
In your deleteLeaveType function, if you prefer using .then to handle async functions you can get rid or async and await like this:
// remove 'async' from function declaration
const deleteLeaveType = id => {
// keep original code
// remove 'await'
CalendarManagementAPI.deleteLeaveType(id)
.then(data => {
// ... everything else the same
};
OR to use async / await the right way, like you used in the first deleteLeaveType in your question, do this:
const deleteLeaveType = async id => {
let deleteLeaveType = isLeaveType.filter(
item => item.id !== id
);
let data = await CalendarManagementAPI.deleteLeaveType(id);
// ... the rest of your code
};
Here's an interesting article explaining some ideas for error handling with async / await, if you're interested: Better error handling with async / await
I would also recommend not using the same variable name deleteLeaveType for two functions and an array. This can get a bit confusing as to what you're referencing at any given moment in time.

React - Returning data from API

I know there are similar questions, but I can't find the answer.
First, please tell me if I'm doing something really wrong
I need to populate my state with data from an API call. This was working fine with code above:
export const GetPlanets = async () => {
const planets = await axios.get(`${BASE_URL}`).catch((e) => {
console.error(e);
})
return planets.data.results
}
But then I needed to make a second call to several links from one json response filed, and I managed to make it work (don't know if it is the correct approach, though)
const GetPlanets = async () => {
let planetas = {}
await axios.get(`${PLANETS_URL}`)
.then((p) => {
planetas = p.data.results
return axios.get(`${FILMS_URL}`)
}).then((f) => {
planetas.films.forEach((v, i) => {
planetas[i].film = f
})
})
})
.catch((e) => {
console.error(e);
})
return planetas
}
This is my component file, where I try to get the object, like I was doing before
useEffect(() => {
const fetchPlanetas = async () => { // ME TRYING...
const planetas = await GetPlanets()
setPlanetas(planetas)
setToShow(planetas[0])
};
fetchPlanetas()
}, [])
But all I get is undefined
You're getting an array of undefined because .map() needs a return value. In both your .map() callbacks, you are not returning anything.
const results = [1, 2, 3, 4]
const results2 = results.map(elem => {
elem = elem + 1
})
console.log(results2)
But, even if you did return something in your .map() callback, GetFilms(f) is asynchronous, so you would not get the results of GetFilms() mapped into the array as you would expect.
You have a couple of options:
If you have access to the API, send the films data along with the rest of the data when you do your first request.
Use async/await and Promise.all() to get responses.

making second api call after getting data from the first api

I have this first API call which gets me some data and once I have got the data from this api , only then I need to make the second api call . It must happen in the series and not parallelly. How can we do this in react ComponentDidMount?
I am listening to firebase .
Let us suppose that the first api gets me a matchId and now we need to use this matchid to make second call just after first api call without any click .
Let us suppose that this is my first firebase call .
const cardsListener =
getDATA()
.onSnapshot( (doc)=>{
console.log("doc is ",doc);
let data = doc.data();
console.log("data",data);
this.setState({
datainstate:data
});
});
Thanks to async/await, you can wait until an action is done.
componentDidMount() {
this.firstApiCall()
}
async firstApiCall() {
await fetch("http://myurl.com", {
method: 'POST',
body: JSON.stringify(data), // data can be `string` or {object}!
headers:{
'Content-Type': 'application/json'
}
})
.then(res => res.json())
.then((responseJson) => {
//if it worked
this.secondApiCall()
})
.catch(error => console.error('Error:', error))
}
secondApiCall() {
}
There are many ways you could do this. My preferred way is to use async await. I'll give an example of how you would use this below.
const getData = async() => {
try {
const apiCall1 = await axios.get(SOME_URL);
const apiCall2 = await axios.get(SOME_URL/apiCall1.data.id)
return apiCall2
} catch(e) {
return e
}
}
It's a silly example but you hopefully get the point. I make my first API call and await the response. Then I make my second API call using some data from the first call then return. You can do whatever logic you want in-between that.
You could also use a callback or promise but I think async await is clearer, and generally less code.
Async Await Documentation - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
Promises Documentation - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Callback Documentation - https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
You can follow something like this:
componentDidMount() {
fetch("apiUrl").then(res => {
//Do whatever you want to do with the response or get the id
const {id} = res;
fetch(`apiUrl/${id}`).then(response => {
// Do anything with the response of the api call here
}).catch(error => {
//Thing to do on error
});
}).catch(err => {
//Thing to do on error of 1st api call
});
}

Async functions using value from a promise

So I know this question is asked a lot, but I'm trying to retrieve a variable that is created within a promise. The examples I've seen on here involve calling .then and using the data there, however what I'm trying to do involves an async function--which i cant use within the .then block.
Here's my code. I'm using the Asana API To call out a lists of tasks that are due. It successfuly logs it. But I want to save the list value from the last block as a variable that I can use elsewhere.
const asana = require('asana');
const client = asana.Client.create().useAccessToken("xxx");
client.users.me()
.then(user => {
const userId = user.id;
// The user's "default" workspace is the first one in the list, though
// any user can have multiple workspaces so you can't always assume this
// is the one you want to work with.
const workspaceId = user.workspaces[0].id;
return client.tasks.findAll({
assignee: userId,
workspace: workspaceId,
completed_since: 'now',
opt_fields: 'id,name,assignee_status,completed'
});
})
.then(response => {
// There may be more pages of data, we could stream or return a promise
// to request those here - for now, let's just return the first page
// of items.
return response.data;
})
.filter(task => {
return task.assignee_status === 'today' ||
task.assignee_status === 'new';
})
.then(list => {
console.log (util.inspect(list, {
colors: true,
depth: null
}));
})
.catch(e => {
console.log(e);
});
If you're open to rewriting your .then()'s as async/await something like this could work for you:
const fetch = require('node-fetch');
async function doit() {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const json = await response.json();
console.log(json);
}
doit();

Chained fetches dependent on each other

Take the following scenario:
I need to show in a table a list with all countries and the population of each country. All data can be queried from here: api.population.io.
Thare are 2 api calls that can help me achieve what i want:
http://api.population.io:80/1.0/countries - returns a list of all existing countries
http://api.population.io:80/1.0/population/{$country}/today-and-tomorrow/ - returns the population of a particular country
As you can see i need to make 2 api calls since the second call is dependant of the name of the country made by the first call. I managed to make it work with the initial api call using fetch by using this code:
fetch('http://api.population.io:80/1.0/countries')
.then(results => {
return results.json();
}).then(data => {
//data.countries
})
This just returns me a list with all the countries.
Now i need to loop through data.countries and make a new api call for each country without breaking the whole process. I tried throwing another fetch call where data.countries is available while looping over data.countries but as you can imagine this breaks up the whole process, what i think happens is that the loop doesn't wait for the fetch call to complete thus messing up the query process.
I'm pretty new to this and i've tried googling it but i'm not sure what i can use to achieve what i need. Any help would be truly appreciated. I've been dealing with this problem the whole day
You could fire all the separate population requests at once and use the result when all of them have finished, with the help of Promise.all:
fetch("http://api.population.io:80/1.0/countries")
.then(results => {
return results.json();
})
.then(data => {
const populationPromises = data.countries.map(country => {
return fetch(
`http://api.population.io:80/1.0/population/${country}/today-and-tomorrow/`
).then(results => results.json());
});
return Promise.all(populationPromises);
})
.then(populations => {
console.log(populations);
})
.catch(error => {
console.error(error);
});
The approach with async/await makes the code more coherent and readable:
function getCountries() {
return fetch('http://api.population.io/1.0/countries/?format=json').then(s => s.json())
}
function getPopulation(country) {
return fetch(encodeURI(`http://api.population.io:80/1.0/population/${country}/today-and-tomorrow/?format=json`)).then(s => s.json())
}
(async () => {
try {
const { countries } = await getCountries();
const populations = await Promise.all(countries.map(getPopulation));
console.log(populations);
} catch(err) {
console.log(err);
}
})();

Categories

Resources