简体   繁体   English

为什么 useDispatch 重新渲染父组件?

[英]Why useDispatch re-renders parent components?

I'm using useDispatch hook (from Redux) in onSelect callback in the Tree component (from Ant library):我在 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)});

Why does useDispatch re-render parent components?为什么useDispatch重新渲染父组件? Is there any way to prevent from this?有什么办法可以防止这种情况发生吗? I tried useCallback like it's in Redux documentation but this solution is to prevent child components from re-rendering, not parents.我在 Redux 文档中尝试过useCallback ,但此解决方案是为了防止重新渲染子组件,而不是父组件。

It looks like my assumption in the comment was correct.看来我在评论中的假设是正确的。

So I will show you the workaround.所以我会告诉你解决方法。
You can extract the part that uses clickValue in the container to another component, say ClickValue .您可以将容器中使用clickValue的部分提取到另一个组件,例如ClickValue

Doing so will isolate the update to ClickValue component only.这样做只会隔离对ClickValue组件的更新。

My fork: https://codesandbox.io/s/soanswer60515755-9cc7u我的叉子: 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>
  );
}

Check out the profile result below.查看下面的配置文件结果。

个人资料结果

I would think that on every render you are redeclaring the onSelect function.我认为在每次渲染时,您都在重新声明 onSelect 函数。 Functions are reference types.函数是引用类型。 Passing that redeclared function with its new reference on ever render will cause a rerender.将重新声明的函数及其新引用传递给 ever render 将导致重新渲染。 Perhaps you should look into using context.也许您应该考虑使用上下文。

My problem with re-rendering components was caused by useSelector used in parent components where I directly refer to state .我重新渲染组件的问题是由在我直接引用state父组件中使用的useSelector引起的。 Most probably because of new result of this selector..很可能是因为这个选择器的新结果..

Solution: I rewrote this selectors with reselect library to make them memoized (it was suggested in one of comments here but I don't know why its've been removed).解决方案:我用reselect 库重写了这个选择器,使它们被记住(这是在此处的评论之一中提出的,但我不知道为什么它已被删除)。 I did exactly what is in redux documentation about memoized selectors .我完全按照 redux 文档中关于memoized selectors 的内容进行了操作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM