API 调用后 ReactJS img 未更新

发布于 2025-01-12 22:54:03 字数 5852 浏览 1 评论 0原文

我现在正在学习 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 标记仍然没有更新

感谢您提前的帮助

编辑:添加了到codesandbox的链接

https://codesandbox.io/s/blissful-thunder-u76vwt?file=/src/App.js

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

心凉 2025-01-19 22:54:03

问题

img 标签在第一次调用时可以很好地加载所有图像,但是,
问题是,当我执行另一个邮政编码并单击搜索时,
文本已更新,但 img 标签(天气图像)未更新(
即第一次搜索 91001 一切看起来都很棒,再次搜索
95133,名称更改为圣何塞,但天气预报图像已更改
不从 91001 更新到 95133)

您始终将预测数据附加到 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>

为了保持干燥,绘制了预测图像。

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

Issue

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

Solution

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"
  />
))}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文