调用useDispatch会触发组件强制重渲染吗?Immer场景下的疑问
问题解答
1. Immer对数组push操作的实际处理
你对Immer写时复制的理解存在偏差:当你对draft.products执行push操作时,Immer会创建新的数组实例。
原数组是不可变的,Immer的draft允许你以“可变”的方式编写逻辑,但背后会生成全新的不可变结构。对于数组的push、pop、splice这类会改变原数组的操作,Immer都会复制原数组并生成新数组,因此state.products的引用会发生变化。这也是为什么ComponentB的useSelector能检测到状态变化,触发重渲染——因为前后两次返回的数组引用不同,严格相等===检查不通过。
2. ComponentA重渲染的原因
useDispatch()本身不会触发组件重渲染,你的情况排除选项a,实际是ComponentA的重渲染源于React的默认渲染机制:
- 如果ComponentA的父组件因为Redux store更新(或其他原因)发生重渲染,那么作为子组件的ComponentA会默认跟着重渲染(除非用
React.memo包裹ComponentA,跳过不必要的重渲染)。 - 你提到“若Immer创建了新数组,ComponentA不应重渲染”的想法是错误的:ComponentB的重渲染不会导致父组件ComponentA重渲染,但父组件的重渲染会传递给子组件。
补充:你的reducer写法修正
注意你当前的reducer写法存在问题:
// 错误写法 const reducer = produce((draft = initialData, action) => { // ... }); // 正确写法:将初始状态作为produce的第二个参数 const reducer = produce((draft, action) => { switch (action.type) { case "Add": draft.products.push(action.payload); break; default: break; } }, initialData);
这样才能确保初始状态被正确设置,避免潜在的状态异常。
内容的提问来源于stack exchange,提问作者user22155685
相关产品推荐
相关产品推荐

