skip to Main Content

I initialize the state to an empty object at first but then in my async function I fetch data from an API containing an object. In the same function I log the data to the console and setState to data, using it in another component as a prop and logging it there. It return one empty object and an object full of my data when I am expecting two objects full of data. Any help?

import Input from "./components/Input";
import "./App.css";
import { useEffect, useState } from "react";
async function fetchLoc(value) {
    const res = await fetch(
      `https://api.openweathermap.org/data/2.5/weather?                             
  q=${value}&appid=${key}&units=imperial`
    );
    const data = await res.json();
    console.log(data);
    setState(data);
  }
  return (
    <div className="App">
      <img src={imgSrc} className="cover-img"></img>
      <Input onFetch={fetchLoc} data={state}></Input>
    </div>
  );
}

export default App;

Here is the other component where I am calling the async function and logging the state.

import "./Input.css";
import { useState, useEffect } from "react";

const Input = (props) => {
  const [val, setVal] = useState("");

  const changeHandler = (e) => {
    setVal(e.target.value);
  };

  const clickHandler = () => {
    props.onFetch(val);
    console.log(props.data.weather);
  };

  return (
    <div>
      <input
        placeholder="🔎 Type in your city... "
        onChange={changeHandler}
      ></input>
      <button onClick={clickHandler}>Click me</button>
    </div>
  );
};

export default Input;

2

Answers


  1. it seems that you’re using the setState method to update the state with the fetched data, but you haven’t declared the state variable or initialized it to an empty object. To fix this, you can add the useState hook to your App component to declare the state variable and initialize it as an empty object.

    try the following:

    import Input from "./components/Input";
    import "./App.css";
    import { useEffect, useState } from "react";
    
    const App = () => {
      const [state, setState] = useState({}); // Initialize state as an empty object
    
      async function fetchLoc(value) {
        const res = await fetch(
          `https://api.openweathermap.org/data/2.5/weather?q=${value}&appid=${key}&units=imperial`
        );
        const data = await res.json();
        console.log(data);
        setState(data);
      }
    
      return (
        <div className="App">
          <img src={imgSrc} className="cover-img"></img>
          <Input onFetch={fetchLoc} data={state}></Input>
        </div>
      );
    };
    
    export default App;
    

    Now I think your state variable is declared and initialized properly.

    In your Input component, when you log props.data.weather, it may not display the fetched data correctly because it takes some time for the API call to complete and update the state so may not be immediately reflected in the props of the child component.

    To address this issue, you can utilize the useEffect hook in your Input component to watch for changes in the props.data. When the props.data changes, you can log the updated props.data.weather value:

    import "./Input.css";
    import { useState, useEffect } from "react";
    
    const Input = (props) => {
      const [val, setVal] = useState("");
    
      const changeHandler = (e) => {
        setVal(e.target.value);
      };
    
      const clickHandler = () => {
        props.onFetch(val);
      };
    
      // Watch for changes in props.data
      useEffect(() => {
        console.log(props.data.weather);
      }, [props.data]);
    
      return (
        <div>
          <input
            placeholder="🔎 Type in your city... "
            onChange={changeHandler}
          ></input>
          <button onClick={clickHandler}>Click me</button>
        </div>
      );
    };
    export default Input;
    

    Now, when you click the "Click me" button, it will trigger the API call, update the state, and log the props.data.weather value when the state changes.

    Login or Signup to reply.
  2. The fetch() call to the API should be placed inside either

    • useEffect()
    • an event handler function for example onSubmit, onClick

    You can fetch the data directly inside the child component. No need to pass a handler from parent to child in this case.

    Here is an implementation:

    import "./Input.css";
    import { useState, useEffect } from "react";
    
    const Input = (props) => {
      const [val, setVal] = useState("");
    
      const changeHandler = (e) => {
        setVal(e.target.value);
      };
    
      const clickHandler = async () => {
        // pass in the key and value query parameters
       const res = await fetch(
          `https://api.openweathermap.org/data/2.5/weather?                             
      q=${value}&appid=${key}&units=imperial`
        );
        const data = await res.json();
        console.log(data);
        // TO DO: assign the data variable to some state variable
      };
    
      return (
        <div>
          <input
            placeholder="🔎 Type in your city... "
            onChange={changeHandler}
          ></input>
          <button onClick={async (e) => await clickHandler()}>Click me</button>
        </div>
      );
    };
    
    export default Input;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search