为啥 useDispatch 重新渲染父组件?
Posted
技术标签:
【中文标题】为啥 useDispatch 重新渲染父组件?【英文标题】:Why useDispatch re-renders parent components?为什么 useDispatch 重新渲染父组件? 【发布时间】:2020-06-16 08:05:58 【问题描述】:我在 Tree 组件(来自 Ant 库)的 onSelect
回调中使用 useDispatch 挂钩(来自 Redux):
export const MyComponent = () =>
const dispatch = useDispatch();
const onSelect = (selectedNode) =>
const selectedItem = selectedNode[0];
dispatch(fetchSelectedItems(selectedItem));
;
return
<Tree
onSelect=onSelect
>
<TreeNode .. />
<TreeNode .. />
<TreeNode .. />
</Tree
export const fetchSelectedItems = (selected: string) =>
(dispatch) =>
axios(
url: `/api/items?id=$selected`,
method: 'GET',
).then(response =>
dispatch(fetchSelectedItemsSuccess(response.data))
).catch((error: any) => throw(error));
为什么useDispatch
会重新渲染父组件?有什么办法可以防止这种情况发生吗?我尝试了 useCallback
就像它在 Redux 文档中一样,但 this solution 是为了防止子组件重新渲染,而不是父组件。
【问题讨论】:
嗨@kriz 欢迎来到堆栈溢出。你能提供fetchSelectedItems
和父母的代码吗? (因为父级使用通过fetchSelectedItems
检索到的数据,所以父级会重新渲染)。 minimal reproducible example 会很棒。
即使我做了一些像dispatch( type: 'SOME_ACTION_NAME' )
这样的“虚拟”调度,也会发生这种情况
【参考方案1】:
我认为在每次渲染时,您都在重新声明 onSelect 函数。函数是引用类型。将重新声明的函数及其新引用传递给曾经渲染将导致重新渲染。也许你应该考虑使用上下文。
【讨论】:
这会导致父级重新渲染吗? 对任何地方的任何道具的任何引用更改都会导致重新渲染 但不是从孩子到父母。 如果您在组件中声明一个函数,任何导致该父级进入渲染周期的状态更改都会生成一个新函数。这就是为什么你不能在函数中进行去抖动并且你需要使用 useCallback 钩子的原因。【参考方案2】:看来我在the comment 中的假设是正确的。
所以我会告诉你解决方法。
您可以将容器中使用clickValue
的部分提取到另一个组件中,例如ClickValue
。
这样做只会将更新隔离到ClickValue
组件。
我的叉子:https://codesandbox.io/s/soanswer60515755-9cc7u
function ClickValue()
const clickValue = useSelector(state => state.value);
console.log(clickValue);
return clickValue;
export default function Container()
return (
<div className="Container">
<h3>Container</h3>
<ParentComponent />
<ClickValue />
</div>
);
查看下面的配置文件结果。
【讨论】:
谢谢。当您需要渲染某些东西时,它会有所帮助。在我的情况下,我需要传递值,所以最后我使用 reselect 库重写了我的选择器,现在它们被 momoized 这解决了我的问题。 不客气,感谢您分享答案。您能否将您的解决方案添加为回复并将其标记为答案?【参考方案3】:我重新渲染组件的问题是由在我直接引用state
的父组件中使用的useSelector
引起的。很可能是因为这个选择器的新结果..
解决方案: 我用reselect library 重写了这个选择器以使它们被记忆(这是在这里的一个 cmets 中提出的,但我不知道为什么它被删除了)。我所做的正是 redux 文档中关于 memoized selectors 的内容。
【讨论】:
以上是关于为啥 useDispatch 重新渲染父组件?的主要内容,如果未能解决你的问题,请参考以下文章