React中componentDidMount无限循环且需保留路由问题排查
解决React路由组件导致的无限渲染循环问题
我来帮你拆解这个问题:你遇到的无限循环,根源是每次父组件render时,你都创建了全新的内联组件(比如InformationFilterPage)。React会把这些每次都不一样的组件视为完全不同的组件类型,所以每次都会卸载旧组件、重新挂载新组件——这下子组件的componentDidMount就会反复执行,里面的API调用又会更新父组件状态,触发父组件重新render,形成了闭环。
而你直接渲染子组件时循环停止,是因为没有了路由的组件替换逻辑,子组件只会挂载一次,但代价是丢失了路由功能。下面是具体的解决方案:
方案1:使用Route的render属性传递props(推荐)
React Router的Route组件提供了render属性,允许你直接渲染已存在的组件并传递props,而不需要创建新的组件。这样既保留路由功能,又不会导致子组件反复挂载。
修改后的父组件代码
import React from "react"; import {HashRouter, Route, Switch, Redirect, Link} from 'react-router-dom'; import Main from './components/main/main.component'; import SecondView from './components/secondview/secondview.component'; import ThirdView from './components/thirdview/thirdview.component'; import Traineeship from './components/traineeship/traineeships.component'; import InformationFilter from "./components/information/information-filter.component"; import InformationJob from "./components/information/information-job.component"; class AppRoutes extends React.Component { constructor(props){ super(props); this.state = { selectedIndustry: '', selectedJob: '', industries: [], jobs: [], industriesPage: 0, }; // 提前绑定setState,避免每次render都生成新函数 this.setRootState = this.setState.bind(this); } render(){ console.log("parent is called..."); return ( <HashRouter> <Switch> <Route exact path='/' component={Main}/> <Route path='/secondview' component={SecondView}/> {/* 用render属性传递props */} <Route path='/traineeships' render={() => ( <Traineeship rootState={this.state} setRootState={this.setRootState} /> )}/> <Route path='/information-filter' render={() => ( <InformationFilter rootState={this.state} setRootState={this.setRootState} /> )}/> <Route path='/information-job' render={() => ( <InformationJob rootState={this.state} setRootState={this.setRootState} /> )}/> <Redirect from='*' to='/' /> </Switch> </HashRouter> ); } } export default AppRoutes;
方案2:优化子组件,修复小bug
另外,我注意到你的子组件InformationFilter里有个小问题:下拉框的value属性写错了,应该从rootState里取,而不是直接从props取,否则选中状态不会正确同步:
修改后的子组件关键部分
// 行业下拉框 <select id={"dropdownList"} onChange={(e) => this.onIndustryChangeOption(e)} value={this.props.rootState.selectedIndustry} // 这里改成rootState里的属性 > {this.props.rootState.industries.map((industry, i) => <option key={i} value={industry.id}>{industry.title}</option> )} </select> // 工作下拉框同理 <select id={"dropdownList"} onChange={(e) => this.onJobChangeOption(e)} value={this.props.rootState.selectedJob} // 同样修正 > {this.props.rootState.industries.map((job, i) => <option key={i} value={job.id}>{job.text}</option> )} </select>
额外优化:避免不必要的重渲染
如果父组件状态变化时子组件频繁重渲染,你可以用React.memo包裹子组件,减少不必要的渲染:
// 在子组件导出时使用React.memo export default React.memo(InformationFilter);
这样修改后,路由功能保留,子组件只会挂载一次,componentDidMount里的API也只会调用一次,无限循环的问题就解决了。
内容的提问来源于stack exchange,提问作者Mizlul
相关产品推荐
相关产品推荐

