Redux连接组件的Props浅比较机制:为何组件不总是重渲染?
你的疑问非常精准,这是对Redux和React-Redux工作机制的常见误解点,我来帮你拆解清楚忽略的几个关键细节:
Redux reducer并非始终返回全新state副本
官方文档强调的是当状态需要更新时必须返回新的state对象,但如果状态没有变化,正确的做法是返回原state的引用。比如你的reducer处理了一个不相关的action,此时应该直接返回传入的state,而不是创建新对象。如果不管状态变没变都返回新对象,才会导致每次触发更新,但这是不符合Redux最佳实践的。React-Redux的浅比较针对
mapStateToProps返回的props,而非整个Redux state
即使Redux返回了新的根state对象,mapStateToProps只会提取你需要的部分属性。假设你的根state是{ user: { name: 'Alice' }, posts: [...] },当你只更新了posts部分,返回新的根state,但user对象的引用还是原来的。如果你的mapStateToProps只取了state.user,那么新旧props中的user引用完全相同,浅比较会判定这个props没有变化,组件就不会重渲染。浅比较的核心是引用相等性
React-Redux默认用shallowEqual函数做浅比较,会逐个对比mapStateToProps返回对象的每个属性:- 对于基本类型(数字、字符串等),比较值是否相等;
- 对于对象/数组,比较的是引用是否相同,而非深层内容。
所以只要mapStateToProps提取的属性引用没变化,不管根state是不是新的,浅比较都会通过,组件就不会触发重渲染。
举个简单的代码例子:
// 初始state const initialState = { user: { id: 1, name: 'Bob' }, todos: [] }; // 处理更新todos的reducer function reducer(state = initialState, action) { switch(action.type) { case 'ADD_TODO': // 返回新的根state,但user引用保持不变 return { ...state, todos: [...state.todos, action.payload] }; default: // 状态无变化时返回原state return state; } } // 组件的mapStateToProps const mapStateToProps = (state) => ({ user: state.user });
当触发ADD_TODO时,根state是新对象,但user的引用和之前完全一致。React-Redux对比新旧props中的user,发现引用相同,因此不会让组件重渲染。
总结来说:关键在于Redux reducer仅在状态变化时返回新对象,且React-Redux只对比你实际用到的props的引用,而非整个根state的引用。
内容的提问来源于stack exchange,提问作者subrat

