React通过props传递数据设置为state后出现undefined报错如何解决?
问题根因
- 接口请求为异步操作,父组件
data初始值是空数组,首次渲染时data[0]为undefined,传入子组件后直接访问weather.temp就会触发属性读取报错 - ActiveWeather组件内部冗余维护了
weather状态,需要通过useEffect同步props,增加了时序问题风险,同时父组件传入的activeWeather参数完全未被使用,导致点击侧边栏切换城市的逻辑失效 - 父组件
activeWeather初始值设为空数组,和后续存储单个天气对象的类型不匹配,存在隐式类型问题
修复方案
1. 父组件App修改
const fetchCity = async (city) => { const res = await axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${key}`); return { description: res.data.weather[0].description, icon: res.data.weather[0].icon, temp: res.data.main.temp, city: res.data.name, country: res.data.sys.country, id: res.data.id, }; }; function App() { const [data, setData] = useState([]); // 初始值改为null,匹配单个对象类型 const [activeWeather, setActiveWeather] = useState(null); useEffect(() => { const fetchCities = async () => { const citiesData = await Promise.all(["Ottawa", "Toronto", "Vancouver", "California", "London"].map(fetchCity)).catch((err) => { console.log(err); }); setData(citiesData || []); // 请求完成后默认选中第一个城市 if(citiesData?.length) setActiveWeather(citiesData[0]) }; fetchCities(); }, []); const handleClick = (event) => { const weather = JSON.parse(event.target.dataset.value); setActiveWeather(weather); }; return ( <div className="App"> <Header /> <Container> <Row> <Col> <WeatherPanel data={data} handleClick={handleClick} /> </Col> <Col> {/* 直接传activeWeather即可,不需要再传data[0] */} <ActiveWeather activeWeather={activeWeather} /> </Col> </Row> </Container> </div> ); } export default App;
2. 子组件ActiveWeather修改
去掉冗余的内部状态,直接用props传入的activeWeather,渲染前做空值判断:
import React from "react"; import { Container, Card } from "react-bootstrap"; const ActiveWeather = ({activeWeather}) => { // 空值时显示加载提示 if(!activeWeather) return <Container><Card><Card.Header>加载中...</Card.Header></Card></Container> return ( <Container> <Card> <Card.Header>{activeWeather.city}, {activeWeather.country}</Card.Header> <Card.Body> <img src={`http://openweathermap.org/img/wn/${activeWeather.icon}@2x.png`} alt="天气图标" /> <p>温度:{activeWeather.temp}</p> <p>天气:{activeWeather.description}</p> </Card.Body> </Card> </Container> ); }; export default ActiveWeather;
3. 子组件WeatherPanel可选优化
原代码里ListGroup.Item嵌套了一层多余的ListGroup.Item,调整结构避免渲染异常:
const WeatherPanel = (props) => { return ( <div> <Container fluid> <Card style={{ boxShadow: "0 0 10px 2px lightgrey" }}> <Card.Header> 常用地点</Card.Header> <ListGroup variant="flush"> {props.data.map((item) => ( <ListGroup.Item key={item.id} data-value={JSON.stringify(item)} onClick={props.handleClick}> <img src={`http://openweathermap.org/img/wn/${item.icon}@2x.png`} alt="天气图标" /> {item.city + ", " + item.country} </ListGroup.Item> ))} </ListGroup> </Card> </Container> </div> ); }; export default WeatherPanel;
内容的提问来源于stack exchange,提问作者zer0day
相关产品推荐
相关产品推荐

