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;
CodePudding user response:
You can use the context API. You would create a context for location. The context's provider would wrap both the search component as well as the component that performs the API call (MainData?) You would set the context value in the search component and get the context value in the MainData component.
The LocationProvider
could look like this:
import React, { createContext, useState } from 'react'
export const LocationContext = createContext(null)
const LocationProvider = ({ children }) => {
const [ location, setLocation ] = useState('')
return (
<LocationContext.Provider value={{location, setLocation}}>
{children}
</LocationContext.Provider>
)
}
export default LocationProvider
If both components are wrapped in this provider, you can access setLocation()
in the SearchComponent
by importing LocationContext
and then doing this:
const { setLocation } = useContext(LocationContext)
and in the other component you can access the location in a similar manner:
const { location } = useContext(LocationContext)
CodePudding user response:
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]);
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>
</>
);
}