Im learning React right now and trying to wrap my head around why my other components updated the information but my img tag has not after the second API call.
Here's my code:
export default function LandingPage() {
const [zipcode, setZipCode] = useState('');
const [loading, setLoading] = useState(false);
const [weatherData, setWeatherData] = useState();
var [cityWeatherData, setCityWeatherData] = useState([]);
var [forecast, setForcast] = useState([]);
return(
<TextField
label='Zip Code'
value={zipcode}
onChange={(e) => { setZipCode(e.target.value) }} />
<Button
sx={{ ml: 3, backgroundColor: '#5F8FFF', color: 'white', '&:hover': { color: '#5F8FFF' } }}
onClick={ () => {
currentWeather(zipcode, apiKey)
.then( async (result) => {
setLoading(true);
await sevenDayWeather(result['coord']['lon'], result['coord']['lat'], apiKey)
.then( (response) => {
response['daily'].forEach( (day) => {
console.log('day forecast: ', day);
console.log('Day Weather: ', day['weather'][0]['icon']);
setForcast( forecast => [...forecast, day['weather'][0]['icon']]);
})
});
});
}}>
Search
</Button>
{loading ?
// console.log('forecast: ', forecast)
<WeatherBox
apiKey={apiKey}
name={weatherData['name']}
lat={weatherData['coord']['lat']}
lon={weatherData['coord']['lon']}
feelsLike={weatherData['main']['feels_like']}
highestTemp={weatherData['main']['temp_max']}
lowestTemp={weatherData['main']['temp_min']}
forecast={forecast}
/> : <></>}
);}
For my WeatherBox
component
export default function WeatherBox(props) {
let newDate = new Date()
let date = newDate.getDate();
let month = newDate.getMonth() + 1;
let year = newDate.getFullYear();
return (
<Box
className='retrievedInformation'
sx={{
mt: 10,
p: 5,
boxShadow: 'gray 5px 10px 10px 5px',
borderRadius: '20px',
textAlign: 'end',
backgroundImage: `url(${sunny})`,
objectFit: 'contain',
backgroundRepeat: 'no-repeat',
backgroundSize: '500px 500px'
}}>
<Typography
sx={{ fontSize: '50px' }}>
{props.name}
</Typography>
<Typography
sx={{ fontSize: '25px' }}>
Today: {month} / {date} / {year}
</Typography>
<img src={`http://openweathermap.org/img/wn/${props.forecast[0]}@2x.png`} alt='forecast image' />
<Box
display='flex'
flexDirection='row'
sx={{ textAlign: 'end', justifyContent: 'end', alignItems: 'end' }}>
<Typography
sx={{ mr: 3, fontSize: '30px', fontWeight: '300', color: 'gray' }}>
Feels Like:
</Typography>
<Typography
sx={{ fontSize: '30px' }}>
{props.feelsLike} F
</Typography>
</Box>
<Box
display='flex'
flexDirection='row'
justifyContent='end'
alignItems='end'
sx={{ textAlign: 'end' }}>
<Typography
sx={{ mr: 3, fontSize: '20px', fontWeight: '300', color: 'gray', textAlign: 'end' }}>
Highest Temperature:
</Typography>
<Typography
sx={{ fontSize: '20px', textAlign: 'end' }}>
{props.highestTemp} F
</Typography>
</Box>
<Box
display='flex'
flexDirection='row'
justifyContent='end'
alignItems='end'>
<Typography sx={{ mr: 3, fontSize: '20px', fontWeight: '300', color: 'gray', textAlign: 'end' }}>Lowest Temperature: </Typography>
<Typography sx={{ fontSize: '20px', textAlign: 'end' }}> {props.lowestTemp} F</Typography>
</Box>
<Box textAlign='end' alignItems='end' justifyContent='end'>
<Typography sx={{ mt: 5, fontSize: '30px' }}>Weather forecast for the next 7 days</Typography>
<img src={`http://openweathermap.org/img/wn/${props.forecast[1]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[2]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[3]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[4]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[5]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[6]}@2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[7]}@2x.png`} alt='forecast image' />
</Box>
</Box>
);
}
My forecast
array has been update as well and holding all the correct values however, the img tag in weatherbox
is still not updating
Thanks for your help in advance
EDIT: Added link to codesandbox
https://codesandbox.io/s/blissful-thunder-u76vwt?file=/src/App.js
The img tag loads all the images fine for the first call however, the problem is that when I do another zipcode and clicked search, the texts updated, but the img tag (the weather images) did not update ( i.e. first search 91001 everything looks great, searched again for 95133, name changed to San Jose but the weather forecast images did not update from 91001's to 95133's)
You always append forecast data to the forecast
state but only reference the first 8 elements.
response["daily"].forEach((day) => {
setForcast((forecast) => [
...forecast, // <-- shallow copy persists old forecast data
day["weather"][0]["icon"]
]);
});
...
<img
src={`http://openweathermap.org/img/wn/${props.forecast[0]}@2x.png`}
alt="forecast image"
/>
...
<img
src={`http://openweathermap.org/img/wn/${props.forecast[1]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[2]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[3]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[4]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[5]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[6]}@2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[7]}@2x.png`}
alt="forecast image"
/>
To resolve, you should overwrite the forecast state when updating.
setForcast(response.daily.map((day) => day.weather[0].icon));
Here's a "optimized" button click handler.
<Button
onClick={async () => {
setLoading(false);
const weather = await currentWeather(zipcode, apiKey);
setWeatherData(weather);
console.log(weather);
const forecast = await sevenDayWeather(
weather.coord.lon,
weather.coord.lat,
apiKey
);
setForcast(forecast.daily.map((day) => day.weather[0].icon));
setLoading(true);
}}
>
Search
</Button>
And for the sake of DRY-ness, mapped forecast images.
{props.forecast.map((id, index) => (
<img
key={index}
src={`http://openweathermap.org/img/wn/${id}@2x.png`}
alt="forecast image"
/>
))}