【问题标题】:React - reusable Redux hook slice issue (Redux Toolkit, Typescript)React - 可重用的 Redux 钩子切片问题(Redux Toolkit,Typescript)
【发布时间】:2021-05-24 17:11:49
【问题描述】:

我正在尝试创建一些挂钩来获取 Redux 存储的切片,以便存储无法直接访问以返回任何内容。

如果我直接在组件中使用Selector,它会很好地工作并且不会不必要地重新渲染:

*** Modal.tsx ***
const { isModalOpen } = useSelector((state: RootState) => state.carsSlice); // Works great. No unnecessary re-renders

如果我创建一个挂钩来返回 carsSlice,那么它会不必要地重新渲染整个页面。为什么?

例如,

*** StateHooks.ts ***
const useGlobalState = () => useSelector((state: RootState) => state);
export const useCarsState = () => useGlobalState().carsSlice;

*** Modal.tsx ***
const { isModalOpen } = useCarsState(); // Re-renders underlying page and is significantly slower than above approach

我正在从状态中获取特定值,所以我不明白为什么它会重新呈现它正在使用的整个页面?有没有办法做到这一点?

我也尝试了以下方法,但它仍然会导致页面重新渲染:

const useCarsState = useSelector((state: RootState) => state.carsSlice); // Same result

它按预期工作的唯一方法是下面但我想要上面的自定义钩子:

const { isModalOpen } = useSelector((state: RootState) => state.carsSlice); // Works great

谢谢大家。

【问题讨论】:

  • 你能分享一个演示codesandbox.io吗? StateHooks 示例不会按预期工作,因为您仍在调用返回整个状态的函数。但最后 2 个示例应该可以工作,所以通过一个工作示例也许我可以提供帮助

标签: reactjs typescript redux redux-toolkit


【解决方案1】:

您可以使用useShallowEqualSelector 它只会在 store 中的值发生变化时重新渲染。

此外,您可以将其放入单独的挂钩中,例如:

import { TypedUseSelectorHook, useSelector, shallowEqual } from "react-redux";
import { RootState } from "store/rootReducer";

const useShallowEqualSelector: TypedUseSelectorHook<RootState> = (selector) =>
  useSelector(selector, shallowEqual);

export default useShallowEqualSelector;

在这种情况下,您可以在任何地方使用此钩子,并且可以访问 typescript 的提示

【讨论】:

  • 哦,我不知道这个!谢谢你。我已经添加了这个,但它似乎仍然重新渲染页面: export const useGlobalState : TypedUseSelectorHook = selector => useSelector(selector, shallowEqual); export const useGeneralState = () => useGlobalState((state: RootState) => state.generalSlice); // 这个用法正确吗? const { open } = useGeneralState();
  • 你应该直接在组件中使用const open = () =&gt; useGlobalState((state: RootState) =&gt; state.generalSlice.open)。如果您想使用export const useGeneralState = () =&gt; useGlobalState((state: RootState) =&gt; state.generalSlice);,则必须查看generalSlice 中的状态,因为在这种情况下,generalSlice 中的所有属性都是可观察的
【解决方案2】:

useSelectordoing reference comparisons of the value you return 工作。如果该值发生变化,它会强制组件重新渲染。

因此,您永远不应该从 `useSelector 返回整个根状态!这将导致组件总是重新渲染。

您稍后对返回的值进行什么额外的解构并不重要 - 重要的是选择器本身返回什么。

这就是为什么您应该始终选择给定组件所需的最小状态片段,以确保它仅在绝对需要时重新渲染,因为它的数据实际上改变了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-03
    • 2022-11-28
    • 2021-02-06
    • 2021-12-05
    • 2021-05-27
    • 2021-12-22
    • 2020-10-08
    • 2020-07-11
    相关资源
    最近更新 更多