-1

I can't figure why I can't update my state (see setCoords). The request returns with a 200 code and the elements I'm trying to retrieve exists : enter image description here

Here is my code :

const App = () => {
    const [city, setCity] = useState("");
    const [forecast, setForecast] = useState(null);
    const [coords, setCoords] = useState({});

    const handleSearchChange = ev => {
        setCity(ev.target.value);
    };

    async function onSearch() {
        if (city) {
            await apiGet(`/geo/1.0/direct?q=${city}`)
                .then(r => r.json())
                .then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything

            await console.log(coords) // console logs {}
            await apiGet(
                `/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
            )
                .then(r => r.json())
                .then(r => setForecast(r));
        }
    }

Thanks for your help!

3 Answers3

0

try useCallback

... 
const onSearch = useCallback(async () {
        if (city) {
            await apiGet(`/geo/1.0/direct?q=${city}`)
                .then(r => r.json())
                .then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything

            await console.log(coords) // console logs {}
            await apiGet(
                `/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
            )
                .then(r => r.json())
                .then(r => setForecast(r));
        }
    }, [coords]);
... 

Refer: https://reactjs.org/docs/hooks-reference.html#usecallback

Shyam
  • 1,364
  • 7
  • 13
0

One thing to note is that don't mix await with then (More on this: Can await and then be mixed in one implementation?). Since you are using async, I recommend you change all to await, like below

Another thing to note is setStates calls (i.e setCoords and setForecast and setCity) is asynchronous by nature, meaning that an immediate console.log after setting state will not log the just-updated value. Instead, React will schedule those setState onto the next render - therefore, you can only see/access the most updated values in the next render cycle. If you want to log values, you can put them as inside a <pre> tag in your HTML, or do console.log at the beginning, like below:

const App = () => {
    const [city, setCity] = useState("");
    const [forecast, setForecast] = useState(null);
    const [coords, setCoords] = useState({});

    console.log("City", city, "Forecast", forecast, "Coords", coords);

    const handleSearchChange = ev => {
        setCity(ev.target.value);
    };

    async function onSearch() {
        if (city) {
            const resNonJson = await apiGet(`/geo/1.0/direct?q=${city}`)
            const resJson = await resNonJson.json())
            const item = resJson[0];
            setCoords({lat: item.lat, lon: item.lon}));

            // Note that `setState` is async so console.log will not get the just-updated value
            console.log(coords) // {}
            console.log(item) // {lat:..., lon:...}
            const resNonJson2 = await apiGet(
                `/data/2.5/onecall?lat=${item.lat}&lon=${item.lon}&exclude=current,minutely,hourly,alerts`
            )
             const resJson2 = await resNonJson2.json())
             setForecast(resJson2);
        }
    }
    ... (other codes that I trust you do correctly)

    return <div>
    <pre>{JSON.stringify(coords)}</pre>
    </div>

Bao Huynh Lam
  • 974
  • 4
  • 12
0

setState() operation is asynchronous in React. All that means that you can't rely on your new state values you apply in setState to be applied immediately. Along with setState, fetch() is also asynchronous in nature.Hence, console.log statement will not wait for the setState() or fetch() to get executed. In such a scenario, you can always handle it by a callback argument of setState().

           await apiGet(`/geo/1.0/direct?q=${city}`)
            .then(r => r.json())
            .then(r => setCoords(data => {lat: r[0].lat, lon:r[0].lon}))

       
Pooja Thapa
  • 83
  • 1
  • 16