React项目WeatherResult组件render()无限循环问题排查
问题产生原因
核心触发点是父组件违反React渲染规则,在render()方法中直接执行了带副作用的数据请求方法,形成了渲染死循环:
- React组件的
render()函数要求是纯函数,执行过程中不能触发任何会改变组件状态、发起数据请求的副作用操作。你的父组件在render方法第一行直接调用了this.fetchFavCities(),每次组件渲染都会执行这个方法。 fetchFavCities()请求完成后会调用setState更新favCts状态,状态变更会触发父组件重新渲染,重新渲染又会再次调用fetchFavCities()发起请求、更新状态,形成「渲染→发请求→更新状态→再次渲染」的无限循环。- 当
displayResult为true时,<WeatherResult />作为父组件的子元素,会跟着父组件的每一次重渲染执行自身的render方法,表现出来就是WeatherResult的render被无限触发。
额外说明:WeatherResult组件本身的生命周期写法没有无限循环问题,它的重复渲染是父组件无限重渲染连带导致的。
修复方案
- 将
fetchFavCities()的调用从render方法中移除,放到父组件的componentDidMount生命周期中执行,该生命周期只会在组件首次挂载完成后触发一次,不会随每次渲染重复执行。修改示例:
// 父组件内新增生命周期方法 componentDidMount() { this.fetchFavCities(); } render() { // 删除原render方法中的 this.fetchFavCities(); 调用 return ( // 原有JSX返回内容保持不变 <div> <form onSubmit={this.handleSubmit}> <div> <div className="column"> { this.state.favCts.map( (item, index) => <button key={index} onClick = {() => {this.fetchFavWeather(item)}}>{item}</button> )} </div> <div className="control"> <input className="input" type="text" placeholder="input city here" onChange={this.handleInputChange} required /> </div> <div className="field"> <div className="control"> <input type='submit' className="button is-light is-large" value='Check Weather' /> <input type='submit' className="button is-light is-large" value='Save as Favourite' onClick = {this.saveAsFavourite}/> </div> </div> </div> </form> <div className="column"> {this.state.displayResult ? <WeatherResult /> : null} </div> </div> ) }
- 可选优化:在
fetchFavCities更新状态前,可以先比对返回的收藏城市列表和现有state.favCts是否完全一致,数据无变化时不调用setState,避免无效重渲染。 - 修复WeatherResult的隐性渲染错误:组件初始化时
days为空数组,接口返回的days是多日预报数组,直接访问this.state.days['datetime']无法获取有效值,需要遍历数组渲染每日预报,或通过days[0]获取指定日期的数据,避免控制台报错。
内容的提问来源于stack exchange,提问作者G lau
相关产品推荐
相关产品推荐

