Reputation: 45
I need a solution for the following sequence:
The browser checks user's Geolocation (assuming he allows that) -> Longitude and Latitude are kept in state and used for 2 API calls -> Google Reverse Geolocation API checks for city name AND at the same time DarkSky API checks for the weather -> third API waits for results from previous calls and uses it as the query for the third, Unsplash API
Here's my code:
const [position, setPosition] = useState({ latitude: '50.049683', longitude: '19.944544' });
const [info, setInfo] = useState({ city: null, weather: null });
const [photos, setPhotos] = useState([]);
useEffect(() => {
const fetchInfo = async () => {
try {
const [cityInfo, weatherInfo] = await Promise.all([
axios.get(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${position.latitude},${position.longitude}&language=en&result_type=locality&key=${GEO_ACC_KEY}`,
),
axios.get(
`https://api.darksky.net/forecast/${WEATHER_ACC_KEY}/${position.latitude},${position.longitude}?exclude=hourly,daily,alerts,flags`,
),
]);
setInfo({
city: cityInfo.data.results[0].address_components[0].short_name,
weather: weatherInfo.data.currently.summary.toLowerCase(),
});
console.log('Info', info); // Results in {city: null, weather: 'null'}
const photosData = await axios.get(
`https://api.unsplash.com/search/photos?query=${info.weather}+${info.city}&page=1&per_page=8&client_id=${UNSPLASH_ACC_KEY}`,
);
setPhotos(photosData.data.results);
console.log('Photos data from API call:', photosData); //Object based on query: "null+null"
console.log('Photos:', photos); // Empty array
} catch (err) {
// Handling errors
}
};
fetchInfo();
}, []);
console.log('Info outside axios get', info); // Results in object with city name and current weather
console.log('photos outside axios get', photos); // Proper result I am looking for
Right now the proper data is available ONLY outside useEffect. It does not provide the data for the third API call (right now Unsplash API call uses "null+null" as a query).
So I headed over to useEffect documentation and it says that a second parameter (an array) takes dependencies and updates when any of the state dependencies change.
I tried using it as follows:
useEffect(() => {
const fetchInfo = async () => {
//rest of the code
},
fetchInfo();
}, [info]);
It uses proper keywords for the API call (city and weather, instead of null null) BUT creates an infinite API calls.
How do I fix that?
Upvotes: 0
Views: 611
Reputation: 281626
State updates are not immediate and will reflect in the next render cycle.
Please check this post for more details on this: useState set method not reflecting change immediately
Also you must note that you want to chain API call and not call the entire useEffect again on info change. Adding info
as a dependency will definitely lead to an infinite loop since info
is being set inside the useEffect.
To solve your problem, You can instead use the value you set to state while making the api call
const newInfo = {
city: cityInfo.data.results[0].address_components[0].short_name,
weather: weatherInfo.data.currently.summary.toLowerCase(),
}
setInfo(newInfo);
console.log('Info', info); // Results in {city: null, weather: 'null'}
const photosData = await axios.get(
`https://api.unsplash.com/search/photos?query=${newInfo.weather}+${newInfo.city}&page=1&per_page=8&client_id=${UNSPLASH_ACC_KEY}`,
);
Upvotes: 1