Search code examples
javascriptreactjsapireact-propsreact-state

How to pass input value from one component to the other component( where api & data display code are )? how to make connection between 2 components?


I have two components where one comp provides a search input field where the user will enter data(e.g; city name) and another comp provides the main weather data( based on the user search input from comp 1) like temp, wind, etc.. how should I pass the user input to the API so it will render the data of that city. I have been stuck on this issue for the last 3 days. any solution?

Comp1 (search comp)

import React, { useState } from "react";
import "../Componentstyle/search.css";
export default function Search() {
  const [location, setLocation] = useState();
  
const handlesubmit = (event)=>{
  event.preventDefault();
  setLocation(event.target.value)
}
  return (
    <>
    <div className="main">
      <nav className="istclass">
        <form className="form">
          <div className="search">
            <input
              value={location}
              placeholder="search city"
              className="searchbox"
              onChange={(e) => setLocation(e.target.value)}
            />

            <button className="nd" type="button" onClick={handlesubmit}>
              Submit
            </button>
          </div>
        </form>
      </nav>
    </div>
    </>
  );
}

Comp2 (maindata comp)

import React, { useState, useEffect } from "react";
import "../Componentstyle/Main.css";
export default function Maindata() {
  const [data, setData] = useState();


  let city = "mansehra";

  let weather = async () => {
    // if(!city)return;
    const key = "XYZ";
    await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}&units=metric&formatted=0`
    )
      .then((response) => response.json())
      .then((actualData) => setData(actualData));
  };
  useEffect(() => {
    weather();
  }, []);

  if (!data) {
    return <div>Loading...</div>;
  }

  const link = `http://openweathermap.org/img/w/${data.weather[0].icon}.png`;

  return (
    <>
    <div className="maindata">
      <div className="city">{data.name}</div>
      <div className="temp">{data.main.temp} C</div>
      <div className="icon">
        <img src={link} alt="not found" />{" "}
      </div>
      <div className="feel">feels Like {data.main.feels_like} C</div>
      <div className="wind">Wind {data.wind.speed} Km/hr</div>
      <div className="cloudy">{data.weather[0].main}</div>
      <div className="humidity">humidity {data.main.humidity}%</div>
      <div className="sunrise">
        sunrise :- {new Date(data.sys.sunrise * 1000).toUTCString()}{" "}
      </div>
      <div className="sunset">
        sunset :- {new Date(data.sys.sunset * 1000).toUTCString()}
      </div>
    </div>
    </>
  );
}

App.js Comp

import "./App.css";
import Maindata from "./Components/Maindata";
import Search from "./Components/Search";



function App() {
  
  return (
    <div className="mainpage">
      <div className="searchComp">
        <Search />
      </div>
      <div className="details">
        <Maindata />

  );
}

export default App;


Solution

  • You can simply Lift State Up. Move the Search component's state up to a common ancestor component and pass the state and state updater callback function down as props to the components needing them.

    Example:

    App

    function App() {
      const [location, setLocation] = useState();
    
      return (
        <div className="mainpage">
          <div className="searchComp">
            <Search {...{ location, setLocation }} />
          </div>
          <div className="details">
            <Maindata city={location} />
          </div>
        </div>
      );
    }
    

    Search

    export default function Search({ location, setLocation }) {
      const handlesubmit = (event) => {
        event.preventDefault();
        setLocation(event.target.value);
      };
    
      return (
        <div className="main">
          <nav className="istclass">
            <form className="form">
              <div className="search">
                <input
                  value={location}
                  placeholder="search city"
                  className="searchbox"
                  onChange={(e) => setLocation(e.target.value)}
                />
    
                <button className="nd" type="button" onClick={handlesubmit}>
                  Submit
                </button>
              </div>
            </form>
          </nav>
        </div>
      );
    }
    

    Maindata

    export default function Maindata({ city = "mansehra" }) {
      const [data, setData] = useState();
    
      const weather = async (city) => {
        const key = "XYZ";
        await fetch(
          `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}&units=metric&formatted=0`
        )
          .then((response) => response.json())
          .then((actualData) => setData(actualData));
      };
    
      useEffect(() => {
        if (city) {
          weather(city); // <-- pass city through to function
        }
      }, [city]);
    
      if (!data) {
        return <div>Loading...</div>;
      }
    
      const link = `http://openweathermap.org/img/w/${data.weather[0].icon}.png`;
    
      return (
        <>
        <div className="maindata">
          <div className="city">{data.name}</div>
          <div className="temp">{data.main.temp} C</div>
          <div className="icon">
            <img src={link} alt="not found" />{" "}
          </div>
          <div className="feel">feels Like {data.main.feels_like} C</div>
          <div className="wind">Wind {data.wind.speed} Km/hr</div>
          <div className="cloudy">{data.weather[0].main}</div>
          <div className="humidity">humidity {data.main.humidity}%</div>
          <div className="sunrise">
            sunrise :- {new Date(data.sys.sunrise * 1000).toUTCString()}{" "}
          </div>
          <div className="sunset">
            sunset :- {new Date(data.sys.sunset * 1000).toUTCString()}
          </div>
        </div>
        </>
      );
    }