React withRouter调用mapStateToProps时match生成新对象问题求助
问题分析与解决方案
嘿,这个问题我之前也踩过坑!咱们来一步步拆解原因和解决办法:
为什么match每次都是新对象?
在你使用的react-router 4.x版本里,withRouter注入的三个核心props中,history和location是react-router内部维护的复用引用对象,所以每次用===比较都会返回true;但match不一样——它是每次路由匹配(哪怕参数完全没变化)时都会重新创建的新对象实例,哪怕里面的params、path等值完全相同,对象引用也会被更新。
而你的mapStateToProps把整个ownProps合并到了返回的props中,再加上react-redux的connect默认用浅比较判断组件是否需要更新,只要match的引用变了,就会触发不必要的重渲染。
解决办法
这里有几个实用的方案,你可以根据自己的业务场景选择:
1. 只提取match里需要的具体字段(最推荐)
不要把整个match对象传到组件props里,而是在mapStateToProps里只提取你实际用到的部分,比如match.params里的某个路由参数:
const mapStateToProps = (state, ownProps) => { // 只拿业务需要的字段,比如路由里的id参数 const { id } = ownProps.match.params; return { ...state, currentItemId: id, // 如果需要其他路由信息,同样只提取具体属性 currentPath: ownProps.location.pathname }; };
这样即使match是新对象,只要你提取的字段值没变,connect的浅比较就会认为props没有变化,不会触发组件重渲染。
2. 自定义shouldComponentUpdate的比较逻辑
如果一定要保留整个match对象,可以在shouldComponentUpdate里手动比较match的内容,而不是直接比较对象引用:
// 先写一个用于比较match内容的工具函数 const isMatchEqual = (matchA, matchB) => { if (!matchA || !matchB) return matchA === matchB; return ( matchA.path === matchB.path && matchA.url === matchB.url && matchA.isExact === matchB.isExact && JSON.stringify(matchA.params) === JSON.stringify(matchB.params) ); }; shouldComponentUpdate = (nextProps) => { // 先判断history和location的引用变化 if (nextProps.history !== this.props.history) return true; if (nextProps.location !== this.props.location) return true; // 手动比较match的内容而非引用 if (!isMatchEqual(nextProps.match, this.props.match)) return true; // 最后用浅比较判断其他业务props的变化 return !shallowEqual(this.props, nextProps); };
注意:用JSON.stringify比较params虽然简单,但性能一般,如果params里有复杂数据,建议手动逐个比较属性。
内容的提问来源于stack exchange,提问作者innek
相关产品推荐
相关产品推荐

