React结合Redux:componentDidUpdate中触发action、设state如何防无限循环
React资源库路由搜索场景:解决同路由参数变化不触发接口 + 避免无限更新深度报错
业务实现背景
项目搭建了全页面通用公共导航栏,导航栏内置资源搜索输入框,相关代码逻辑如下:
导航栏搜索输入框
<input placeholder="Search Assets" type="text" id="searchTerm" onChange={this.searchAsset} value={this.state.searchValue} />
导航栏输入框绑定的onChange处理逻辑
输入框值变化后更新本地搜索状态,当输入内容去除首尾空格后长度大于2时,跳转资源库页面并携带搜索词作为路由查询参数:
searchAsset = event => { const searchValue = event.target.value; this.setState({ searchValue }); if (searchValue.trim().length > 2) { this.props.history.push(`/company/library?q=${searchValue}`); } };
资源库页面原有实现
最初在componentDidMount生命周期中解析路由查询参数,设置本地搜索状态后触发搜索资源的Redux action:
componentDidMount() { const params = new URLSearchParams(this.props.location.search); const q = params.get("q"); this.setState({ searchValue: q }); this.props.actions.searchAssets({ page: 0, searchString: q }); }
现存问题
首次搜索“image”并获取结果后,清空导航栏输入内容、再次输入“download”触发搜索时,后端无接口响应。
- 根因:同一路由下的组件不会在路由参数变化时重新触发
componentDidMount执行,原有搜索逻辑无法被再次触发。
初次改造的报错问题
为适配参数变化的搜索场景,尝试将搜索逻辑迁移至componentDidUpdate生命周期,对比新旧搜索参数、参数变化时触发搜索action,写出的实现如下:
componentDidUpdate(prevProp, prevState) { const params = new URLSearchParams(this.props.location.search); const q = params.get("q"); if (q !== prevState.searchValue) { this.props.actions.searchAssets({ page: 0, searchString: q }); } }
改造后页面直接触发**Maximum update depth exceeded(超出最大更新深度)**报错。
报错根因
- 对比逻辑错位:本该对比前后两次路由的查询参数判断搜索词是否变化,却拿当前路由参数和上一次渲染的本地state值做对比,判断条件长期成立。
- 状态同步缺失:路由参数变化后,资源库组件本地维护的
searchValue没有同步为最新值,后续任意一次重渲染(比如Redux状态更新、props变化)触发componentDidUpdate时,都会因为参数值不匹配再次触发搜索action,形成“触发重渲染→进生命周期→触发action→Redux状态更新→重渲染”的无限循环。
正确实现方案
调整对比逻辑,以路由props的前后值作为搜索词变化的判断依据,在参数真正变化时同步本地状态、触发搜索action:
componentDidUpdate(prevProps) { // 解析当前路由和上一次路由的搜索参数 const currentQ = new URLSearchParams(this.props.location.search).get("q"); const prevQ = new URLSearchParams(prevProps.location.search).get("q"); // 仅当两次的搜索词真正发生变化时,执行后续逻辑 if (currentQ !== prevQ) { // 同步本地搜索状态 this.setState({ searchValue: currentQ }); // 触发资源搜索action this.props.actions.searchAssets({ page: 0, searchString: currentQ }); } }
方案原理
- 对比基准可靠:以
prevProps中存储的上一次路由参数作为对比基准,只有当路由携带的搜索词真的发生变化时,才会进入逻辑分支,从根源上避免无意义的逻辑触发。 - 打破循环:进入分支后同步本地state、触发搜索action,当Redux搜索结果返回导致组件重渲染时,前后两次的路由参数值完全相等,判断条件不再成立,不会重复调用
setState或触发action,彻底避免无限更新深度报错。
原有
componentDidMount的初始化逻辑可以完整保留,和componentDidUpdate的新逻辑不存在冲突,可覆盖首次进入资源库页面的搜索初始化场景。
内容的提问来源于stack exchange,提问作者chaitanya gupta
相关产品推荐
相关产品推荐

