I need some help getting data from an API call

135 views Asked by At

I'm sure I'm just doing something stupid, but I can't figure out what I'm doing wrong.

When the user fills out their state and city and hits submit, that should run a fetch request for lat and lon values, then that needs to be fed into another API that gives the weather based on lat and lon. I'm using react.js.

import {React, useState} from 'react'

export default function Home () {
    // // GeoApify gets Lat/Long
    // const geo = fetch(`https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`)
    // // OpenWeatherApi One Call API 3.0 gets the weather of the Lat/Long
    // const weather = fetch(`https://api.openweathermap.org/data/3.0/onecall?lat=${coord.lat}&lon=${coord.lon}&appid=544ce8f74a895e6f7bd6425293b01b47`)

    const [coord, setCoord] = useState({lat:'', lon:''})
    const [details, setDetails] = useState({city:'', state:''})

    const fetch = (req, res) => {
        fetch(`https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`)
        .then((res) => res.json())
        .then(fetch(`https://api.openweathermap.org/data/3.0/onecall?lat=${res.results.lat}&lon=${res.results.lon}&appid=544ce8f74a895e6f7bd6425293b01b47`))
        .then((res) => res.json())
        .then(weather.push(res))
    }
    const weather = []
    return(
        <div>
            <h4>Home</h4>
            <form id='form'>
                <p><label htmlFor='city'>City: </label>
                <input placeholder='City' type='text' name='city' onChange={e => setDetails({...details, city:e.target.value}, console.log(details))} value={details.city} /></p>
                <p><label htmlFor='state'>State: </label>
                <input placeholder='State' type='text' name='state' onChange={e => setDetails({...details, state:e.target.value}, console.log(details))} value={details.state} /> </p>
                <p><input type='submit' value='Submit' onSubmit={fetch()} /></p>
            </form>
        </div>
    )
}

I keep getting an error that says:

"Uncaught RangeError: Maximum call stack size exceeded".

Why does it seem to be looping? It also seems to be calling the "fetch" function before the form is submitted.

For reference this is what a call from the lat/lon API looks like:

{
"results": [
{
"datasource": {},
"country": "United States",
"country_code": "us",
"state": "Georgia",
"county": "Gwinnett County",
"city": "Snellville",
"town": "Snellville",
"lon": -84.0199108,
"lat": 33.857328,
"state_code": "GA",
"distance": 0,
"formatted": "Snellville, GA, United States of America",
"address_line1": "Snellville, GA",
"address_line2": "United States of America",
"category": "administrative",
"timezone": {
"name": "America/New_York",
"offset_STD": "-05:00",
"offset_STD_seconds": -18000,
"offset_DST": "-04:00",
"offset_DST_seconds": -14400,
"abbreviation_STD": "EST",
"abbreviation_DST": "EDT"
},
"result_type": "city",
"rank": {
"importance": 0.5276231202788444,
"popularity": 3.3564440571456937,
"confidence": 1,
"confidence_city_level": 1,
"match_type": "full_match"
},
"place_id": "5195b5f237460155c059f9f884ecbced4040f00101f90127d3010000000000c00208",
"bbox": {
"lon1": -84.042913,
"lat1": 33.818392,
"lon2": -83.950932,
"lat2": 33.89217
}
}
],
"query": {}
}

I just need the lat/lon from it.

3

There are 3 answers

1
Konrad On
import { React, useState } from "react";

export default function Home() {
  const [coord, setCoord] = useState({ lat: "", lon: "" });
  const [details, setDetails] = useState({ city: "", state: "" });

  const fetch = (req, res) => {
    fetch(
      `https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`
    )
      .then((res) => res.json())
      .then(
        fetch(
          `https://api.openweathermap.org/data/3.0/onecall?lat=${res.results.lat}&lon=${res.results.lon}&appid=544ce8f74a895e6f7bd6425293b01b47`
        )
      )
      .then((res) => res.json())
      .then((data) => {
        const { lat, lon } = data.results[0];
        setCoord({ lat, lon });
      });
  };
  return (
    <div>
      <h4>Home</h4>
      <form id="form">
        <p>
          <label htmlFor="city">City: </label>
          <input
            placeholder="City"
            type="text"
            name="city"
            onChange={(e) =>
              setDetails(
                { ...details, city: e.target.value },
                console.log(details)
              )
            }
            value={details.city}
          />
        </p>
        <p>
          <label htmlFor="state">State: </label>
          <input
            placeholder="State"
            type="text"
            name="state"
            onChange={(e) =>
              setDetails(
                { ...details, state: e.target.value },
                console.log(details)
              )
            }
            value={details.state}
          />{" "}
        </p>
        <p>
          <input type="submit" value="Submit" onSubmit={fetch()} />
        </p>
      </form>
    </div>
  );
}
1
CtrlSMDFK On

i took your code and made some changes, now it's functional.

import React from "https://cdn.skypack.dev/[email protected]";
import ReactDOM from "https://cdn.skypack.dev/[email protected]";

function App() {
    const [coord, setCoord] = React.useState({ lat: "", lon: "" });
    const [details, setDetails] = React.useState({ city: "", state: "" });
    const fetchFunction = async (event) => {
//         here you should have your preventDefault function, as I said, you receive an event object as paramater in callback function when onSubmit is fired
        event.preventDefault();
        // this is your first request and from this u should parse your data
        try {
            const response = await (await fetch(
                `https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&                        apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`
            )).json();

            console.log('res', response);
            // and here you should do your second fetch in the same maner
        } catch (error) {
            console.log('eerr', error);
        }
    };

    const weather = [];
    return (
        <div>
            <h4>Home</h4>
            {/* I moved your callfunction on form because here it was refreshing your page */}
            <form id="form" onSubmit={fetchFunction}>
                <p>
                    <label htmlFor="city">City: </label>
                    <input
                        placeholder="City"
                        type="text"
                        name="city"
                        {/* here I made a little change, it was correct and functional but i wannted to be the best practice here, setState can take as parameter a new value or a callback with his previous value as paramater  */}
                        onChange={(e) =>
                            setDetails((previousValue) => ({
                                ...previousValue,
                                city: e.target.value
                            }))
                        }
                        value={details.city}
                    />
                </p>
                <p>
                    <label htmlFor="state">State: </label>
                    <input
                        placeholder="State"
                        type="text"
                        name="state"
                        onChange={(e) =>
                            setDetails((previousValue) => ({
                                ...previousValue,
                                state: e.target.value
                            }))
                        }
                        value={details.state}
                    />
                </p>
                <p>
                    <input type="submit" value="Submit" />
                </p>
            </form>
        </div>
     );
}

ReactDOM.render(<App />, document.getElementById("root"));

3
CtrlSMDFK On

Well... Frist of all, your code form is a little bit messy, you should declare an async function to handle the submit request. Then you should have something like this:

// I renamed fetch to fetchFunction because fetch is an already function in node18 or browser
const fetchFunction = async () => {
    // this is your first request and from this u shoul parse your data
    try {
        const response = await(await fetch(`https://api.geoapify.com/v1/geocode/search?city=${details.city}&state=${details.state}&format=json&apiKey=27a84d7b0c1b4d52b41acc3e82bbe239`)).json();

        // and here you should do your second fetch in the same maner
    } catch (error) {
        console.log(error)
    }
}

That error is popping out because you have a memory leak here:

<input type='submit' value='Submit' onSubmit={fetch()} />

and the right form for this is (or "onSubmit={fetchFunction}" if you take my approach):

<input type='submit' value='Submit' onSubmit={fetch} />