React Native中mapStateToProps触发组件频繁重新渲染问题求助
问题根本原因
react-redux中connect高阶组件对mapStateToProps返回的对象默认执行浅对比:只会对比返回对象每一层属性的引用是否相等。你当前写法每次执行mapStateToProps时都会通过解构语法const {contentLoading, ...exploreData} = state.explore生成一个全新的exploreData对象,哪怕state.explore本身没有发生任何变化,这个新对象的引用也和上一次返回的不一样,浅对比判定为数据变化,就会反复触发mapStateToProps执行和组件重渲染。
而你之前用useSelector的写法是直接返回state.explore本身,useSelector默认用严格相等===做对比,只有当state.explore的引用真的发生变化时才会触发重渲染,所以运行正常。
解决方案
方案1:调整返回结构,避免生成多余新对象
如果你不需要单独拆分contentLoading,可以直接返回完整的explore对象,和你之前useSelector的逻辑保持一致:const mapStateToProps = (state) => { console.log('mapStateToProps'); return { explore: state.explore, token: state.auth.token, }; };组件内需要用到
contentLoading的时候直接从props.explore.contentLoading取即可,其余属性也从props.explore取,避免额外的解构生成新对象。方案2:使用reselect创建记忆化选择器
如果你确实需要拆分contentLoading和exploreData,可以用reselect来缓存计算结果,只有当state.explore真的变化时才会重新生成exploreData对象:import { createSelector } from 'reselect'; const selectExplore = state => state.explore; const selectExploreSplit = createSelector( [selectExplore], (explore) => { const {contentLoading, ...exploreData} = explore; return { contentLoading, exploreData }; } ); const mapStateToProps = (state) => { console.log('mapStateToProps'); const { contentLoading, exploreData } = selectExploreSplit(state); return { contentLoading, exploreData, token: state.auth.token, }; };方案3:自定义对比逻辑
你也可以在connect的第四个参数options里自定义对比逻辑,跳过对exploreData的浅对比,改为按需对比:// 深对比可以直接用lodash的isEqual方法 import _ from 'lodash'; export default connect(mapStateToProps, null, null, { areMergedPropsEqual: (nextProps, prevProps) => { return nextProps.contentLoading === prevProps.contentLoading && nextProps.token === prevProps.token && _.isEqual(nextProps.exploreData, prevProps.exploreData) } })(YourComponent)
内容的提问来源于stack exchange,提问作者SDB_1998

