代码之家  ›  专栏  ›  技术社区  ›  tobiasBora

Redux工具包:我应该同时使用useSelector和useCallback吗

  •  0
  • tobiasBora  · 技术社区  · 2 年前

    我以前使用 useSelector 来自Redux,使用以下内容:

      const todo = useSelector((state) => state.todos[props.id])
    

    如文件所示。然而,在另一个名为 proxy-memorize ,他们建议使用(用于自己的库):

    useSelector(useCallback(memoize(state => ({ … }))))
    

    但现在我很困惑:我应该用吗 useCallback 在…内 使用选择器 通常当我不使用代理记忆时?如果不是,为什么代理记忆需要它?

    0 回复  |  直到 2 年前
        1
  •  1
  •   Drew Reese    2 年前
    useSelector(useCallback(memoize(state => ({ … }))))
    

    但现在我很困惑:我应该用吗 useCallback 在…内 useSelector 通常当我不使用时 proxy-memorize ?

    一般来说,不需要,您不需要通过 使用回调 useSelector((state) => state.todos[props.id]) 很好。React redux和 使用选择器 钩子应用了一些 equality checks during updates 。斜体和粗体的文本强调是我的,以强调我认为与选择器函数参考稳定性相关的内容。

    当功能组件渲染时,提供的选择器功能 将被调用,其结果将从 useSelector() 钩( 缓存的结果 也许 被钩子退回而不重新运行 选择器,如果是 相同的函数引用 与以前一样 组件的渲染。 )

    然而当动作被分派到Redux商店时, 使用选择器() 仅当出现选择器结果时才强制重新渲染 与上一个结果不同。默认比较是 严格的 === 参考比较。

    如果不是,为什么代理记忆需要它?

    还请注意,从文档中可以看出

    具有 使用选择器() ,每次都会返回一个新对象 默认情况下强制重新渲染。

    其中一个建议的解决方案是

    使用Reselect或类似库创建一个记忆选择器 在一个对象中返回多个值,但只返回一个新对象 当其中一个值发生更改时。

    使用 useSelector(state => ({ … })) 即使返回的对象是等效的,也会触发强制重新应答。这个 memoize 函数来自 proxy-memoize 用于 记忆返回的结果 ,并将其包裹在 使用回调 钩子用于记忆, 一个稳定的函数参考 使用选择器 useSelector(useCallback(memoize(state => ({ … })))) 通过记忆(A)选择器回调函数和(B)选择器函数结果,提供了最广泛形式的稳定性优化。中的注释 usage with react redux 部分如果您不使用,这是建议使用的模式 reselect

    我从来没有听说过代理记忆,但代码的重新选择版本可能如下所示:

    import { createSelector } from 'reselect'; // *
    
    const selectTodos = state => state.todos;
    
    export const selectTodoById = createSelector(
      [todos, (state, id) => id],
      (todos, id) => todos[id],
    );
    
    const todo = useSelector((state) => selectTodoById(props.id))
    

    这个 selectTodoById 选择器功能是一个记忆选择器,例如记忆所选 todo 对象使用 state.todos 并通过 id 值作为输入。只有当这两个值中的任何一个发生更改时,选择器函数才会重新计算其值,否则它只返回存储的值。

    *注: 如果您使用的是Redux Toolkit,它会重新导出所有 Reselect (的相同维护者 Redux , React-Redux Redux-Toolkit 还维护 重新选择 ):

    import { createSelector } from '@reduxjs/toolkit';