I'm having a problem, it's been a few days, I'm studying about React and Typescript and I'm developing a temperature application, I'm stopped in a part, where I want the user to click on the submit form, the information that was typed in the input is passed to another component.
Follow my two codes below
CityWeatherSearch.tsx
import { MagnifyingGlass } from 'phosphor-react'
import { FormEvent, useCallback, useRef, useState } from 'react';
import * as Styled from './style'
export function CityWeatherSearch(){
const inputRef = useRef<HTMLInputElement>(null);
const [city,setCity] = useState('');
function handleClick(event:FormEvent) {
event.preventDefault();
const inputCity = inputRef?.current?.value;
console.log({
inputCity, city
});
}
return(
<>
<Styled.BoxSearchCity>
<div className="headerSearch">
<form>
<input type="text" placeholder='Procurar Cidade...' ref={inputRef} onChange={
event => setCity(event.target.value)} />
<button type="submit" onClick={handleClick}>
<MagnifyingGlass/>
</button>
</form>
</div>
<div className="bodySearch">
{city}
</div>
</Styled.BoxSearchCity>
</>
)
}
MainWeatherLive.tsx
import {Clock} from 'phosphor-react'
import { useFetch } from '../../GetData/useFetch'
import * as Styled from './style'
type DataWeather = {
name: string,
condition:{
text:string,
icon:string
},
temp_c:number,
hour:[{
temp_c:number,
time:string,
condition:{
text:string,
icon:string
}
}]
}
export function MainWeatherLive(){
const {dataLocation: dataWeatherApi, isFetching, dataCurrent:dataCurrentApi, dataForecast:forecastApi}
= useFetch<DataWeather>('/v1/forecast.json?key=aff6fe0e7f5d4f3fa0611008221406&q=Guarulhos?days=1&aqi=no&alerts=no');
return(
<>
<Styled.HeaderBox>
<h6>Weather Now</h6>
</Styled.HeaderBox>
<Styled.Container>
{isFetching &&
<p>Carregando...</p>
}
<div className="mainInformation">
<div className="temperatura">
<span>{dataCurrentApi?.temp_c}º</span>
</div>
<div>
A cidade é {cityName}
</div>
<div className="boxCidade">
<div className="cidade">
<span>{dataWeatherApi?.name}</span>
</div>
<div className="tempoHoras">
<span>
{new Date().toLocaleTimeString('pt-BR',{hour12:false, hour:'numeric',minute:'numeric'})} - {new Date().toLocaleDateString()}
</span>
</div>
</div>
<div className="iconeTem">
<img src={dataCurrentApi?.condition.icon} alt={dataCurrentApi?.condition.text} />
</div>
</div>
<div className="footerBox">
<div className="headerFooter">
<Clock/>
<span>Horários</span>
</div>
<div className="listaHorarios">
<ul className="boxTT">
{
forecastApi?.hour?.map(weatherA =>{
const hourTemp = weatherA.time.split(" ")[1].replace(":00","");
const hourTempNumber:number = hourTemp;
const hourNow = new Date().getHours();
return(
<>
{
hourTempNumber == hourNow &&
<li>
<div className="titulo" key={weatherA.temp_c}>
<span>{hourTempNumber}</span>
</div>
<div className="temperatura">
<img src={weatherA.condition.icon} alt={weatherA.condition.text} />
<span>{dataCurrentApi?.temp_c}º</span>
</div>
</li>
}
{
hourTempNumber > hourNow &&
<li>
<div className="titulo" key={weatherA.temp_c}>
<span>{hourTempNumber}</span>
</div>
<div className="temperatura">
<img src={weatherA.condition.icon} alt={weatherA.condition.text} />
<span>{weatherA.temp_c}º</span>
</div>
</li>
}
</>
)
})
}
</ul>
</div>
</div>
</Styled.Container>
</>
)
}
Weather.tsx
import { CityWeatherSearch } from "./WeatherC/CityWeatherSearch";
import { MainWeatherLive } from "./WeatherC/MainWeatherLive";
import { WeatherDetails } from "./WeatherC/WeatherDetails";
import coldImage from '../assets/cold.jpg'
import sunImage from '../assets/sun.jpg'
import rainImage from '../assets/rain.jpg'
import nightVideo from '../assets/night.mp4'
import night from '../assets/night.jpg'
export const TypesWeather = {
NIGHT:{
video:{
source: nightVideo
},
image:{
source: night
}
},
OVERCAST:{
video:{
source: nightVideo
},
image:{
source: night
}
},
COLD:{
image:{
source: coldImage,
title: 'Frio'
}
},
SUN:{
image:{
source: sunImage,
title: 'Verão'
}
},
RAIN:{
image:{
source: rainImage,
title: 'Chuva'
}
},
};
export type TypesWeatherV2 = keyof typeof TypesWeather;
export function Weather(){
return (
<>
<div className="globalSite" style={{background:`linear-gradient(to bottom,rgba(0,0,0,.85) 0,rgba(0,0,0,.85) 100%),url(${TypesWeather.RAIN.image.source})`}}>
</div>
<div className="boxAllWeather">
<div className="backgroundWeather" style={{backgroundImage:`url(${TypesWeather.RAIN.image.source})`}}></div>
<div className="boxAllInff">
<div className="mainWeather">
<MainWeatherLive />
</div>
<div className="otherInfoWeather">
<CityWeatherSearch />
<WeatherDetails />
</div>
</div>
</div>
</>
)
}
I want to pass the city typed in CityWeatherSearch.tsx to MainWeatherLive.tsx. Where is the space 'A cidade é {cityName}' reserved, I've tried everything, but I haven't been able to, could you help me?
CodePudding user response:
You can do this in several ways:
- parent -> child : use props
- child -> parent : use callback/event emitter
- no direct relationship : consider using state management tool like redux
CodePudding user response:
Just lift your state uo to the parent component and pass if to the cild components as props:
function WeatherPage() {
const [city,setCity] = useState('');
return (
<>
<CityWeatherSearch city={city} setCity={setCity}/>
//...
<MainWeatherLive city={city}/>
//...
</>
)
}
function CityWeatherSearch({city, setCity}) {
// your code here, only without const [city, setCity] useState()
}
function MainWeatherLive({city}) {
// your code here, now you can access city
}
If your two components don't have a direct common parent and you don't want to pass down city
and setCity
through a deep component hierarchy, think about using useContext
to share state within your application.