API 调用后 ReactJS img 未更新

ReactJS img not updating after API Call

我现在正在学习 React 并试图解决为什么我的其他组件更新了信息但我的 img 标签在第二次 API 调用后没有更新的原因。

这是我的代码:

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}
            /> : <></>}
);}

对于我的 WeatherBox 组件

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>
);
}

我的 forecast 数组也已更新并保存所有正确的值,但是 weatherbox 中的 img 标签仍然没有更新

提前感谢您的帮助

编辑:添加 link 到 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)

您始终将预测数据附加到 forecast 状态,但仅引用前 8 个元素。

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"
/>

解决方案

解决,更新时应该覆盖预测状态。

setForcast(response.daily.map((day) => day.weather[0].icon));

这是一个“优化的”按钮点击处理程序。

<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>

并且为了 DRY-ness,映射预测图像。

{props.forecast.map((id, index) => (
  <img
    key={index}
    src={`http://openweathermap.org/img/wn/${id}@2x.png`}
    alt="forecast image"
  />
))}