React组件状态更新异常:父组件数据变更时子组件未同步
问题原因与解决方案
你的推测完全正确——问题出在Tomorrow.jsx的useEffect依赖数组为空,它只会在组件首次挂载时执行一次。当父组件传递的props.tomorrowForcast更新时,这个useEffect不会重新触发,导致本地状态tomorrowForcast始终停留在初始计算结果,没有同步新数据。
修复方案1:修正useEffect依赖项
把props.tomorrowForcast加入useEffect的依赖数组,这样每次props更新时,都会重新计算明日预报数据并更新状态:
const [tomorrowForcast, setTomorrowForcast] = useState([]) useEffect(function () { // 先判断props数据是否存在,避免空值报错 if (!props.tomorrowForcast?.list) return; const forcastArray = props.tomorrowForcast.list; const today = new Date(); // 计算明日的日期(处理月末跨月情况,比如今天是31号,直接+1会变成32,用Date对象自动处理) const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const tomorrowDateStr = tomorrow.toISOString().split('T')[0]; // 格式化为YYYY-MM-DD const newTomorrowForecasts = forcastArray.filter(forcast => { // 提取预报数据的日期部分 const forecastDateStr = forcast.dt_txt.split(' ')[0]; // 直接比对完整日期字符串,避免只比对日数的bug(比如月末31号+1变成32,slice(8)会出错) return forecastDateStr === tomorrowDateStr; }); setTomorrowForcast(newTomorrowForecasts); }, [props.tomorrowForcast]); // 加入依赖项,props变化时重新执行 const forcasts = tomorrowForcast.map(forcast => { let tomorrowObj = {...forcast, identifier: 'tomorrow'} const get_dt = forcast.dt_txt const split_dt = get_dt.split(" ") const get_time = split_dt[1] const time = get_time.slice(0, 5) return ( <WeatherBlock {...tomorrowObj} d_or_t={time} /> ) })
优化方案2:移除本地状态,直接在渲染时计算
如果不需要把筛选后的结果存为状态,完全可以直接在渲染阶段计算,彻底避免状态不同步的问题:
// 移除useState和useEffect,直接在渲染时处理 const getTomorrowForecasts = () => { if (!props.tomorrowForcast?.list) return []; const today = new Date(); const tomorrow = new Date(today); tomorrow.setDate(today.getDate() + 1); const tomorrowDateStr = tomorrow.toISOString().split('T')[0]; return props.tomorrowForcast.list.filter(forcast => { const forecastDateStr = forcast.dt_txt.split(' ')[0]; return forecastDateStr === tomorrowDateStr; }); }; const forcasts = getTomorrowForecasts().map(forcast => { let tomorrowObj = {...forcast, identifier: 'tomorrow'} const get_dt = forcast.dt_txt const split_dt = get_dt.split(" ") const get_time = split_dt[1] const time = get_time.slice(0, 5) return ( <WeatherBlock {...tomorrowObj} d_or_t={time} /> ) })
额外说明
原代码中的日期判断逻辑有潜在bug:比如今天是当月最后一天(10月31日),date2会变成32,而预报数据中的日期日数最大是31,这时候永远匹配不到。改用Date对象处理日期,可以自动处理跨月情况,确保逻辑正确。
内容的提问来源于stack exchange,提问作者Jack_T
相关产品推荐
相关产品推荐

