reactjs - 如何使用重新选择和 typescript 创建自定义相等函数?

标签 reactjs typescript redux reselect

如果输入选择器未能通过严格的相等检查,标准的重新选择选择器会使它的内存值无效并重新计算它:

export const selectEmailsFromComments = createSelector(
  selectComments, // returns an array of comments
  comments => commentsToEmails(comments)
)

由于注释是一个数组而不是原始值,并且 redux reducers 倾向于创建一个新的状态来避免副作用,上述内容似乎从未真正记住,因为 selectComments 返回的注释数组总会有不同的引用。

要解决这个问题,可以创建一个 custom selector creator ,例如引入浅等式检查:

const createShallowEqualSelector = createSelectorCreator(
  defaultMemoize,
  shallowEqual
)

export const selectEmailsFromComments = createShallowEqualSelector(
  selectComments, // returns an array of comments
  comments => commentsToEmails(comments)
)

如果评论确实是简单的对象,并且我们希望在任何评论的 Prop 发生更改时重新计算电子邮件,则此方法有效。

但是,如果我们只想重新计算电子邮件,例如评论数变了?我们如何实现自定义相等性检查?我希望以下内容起作用:

type ComparisonFunction<B extends object = {}> = (prev: B, next: B, index: number) => boolean

const createCustomEqualSelector = <B extends object = {}>(
  equalFn: ComparisonFunction<B>
) => createSelectorCreator<ComparisonFunction<B>>(defaultMemoize, equalFn)

const commentsEqualFn = (a: IComment[], b: IComment[], index: number) =>
  a.length === b.length

export const selectEmailsFromComments = createCustomEqualSelector(
  commentsEqualFn
)(
  selectComments, // returns an array of comments
  comments => commentsToEmails(comments)
)

但是,这会为 defaultMemoize 返回以下 Typescript 错误:
(alias) function defaultMemoize<F extends Function>(func: F, equalityCheck?: (<T>(a: T, b: T, index: number) => boolean) | undefined): F
import defaultMemoize
Argument of type '<F extends Function>(func: F, equalityCheck?: (<T>(a: T, b: T, index: number) => boolean) | undefined) => F' is not assignable to parameter of type '<F extends Function>(func: F, option1: ComparisonFunction<B>) => F'.
  Types of parameters 'equalityCheck' and 'option1' are incompatible.
    Type 'ComparisonFunction<B>' is not assignable to type '<T>(a: T, b: T, index: number) => boolean'.
      Types of parameters 'prev' and 'a' are incompatible.
        Type 'T' is not assignable to type 'B'.ts(2345)

我将如何解决自定义重新选择 createSelector 相等函数的这种类型错误?

最佳答案

以下对我有用,但我不确定这是否是最好的方法。

import {
  createSelectorCreator,
  defaultMemoize,
} from 'reselect';

type IComment = { id: number };
type State = { comments: IComment[] };
type CompareFn = <T>(a: T, b: T, index: number) => boolean;
const createCustomEqualSelector = (equalFn: CompareFn) =>
  createSelectorCreator(defaultMemoize, equalFn);
const selectComments = (state: State) => state.comments;
const commentsEqualFn: CompareFn = (a, b, index) =>
  //need to cast it or get an error:
  //  Property 'length' does not exist on type 'T'
  ((a as unknown) as IComment[]).length ===
  ((b as unknown) as IComment[]).length;

export const selectEmailsFromComments = createCustomEqualSelector(
  commentsEqualFn
)(
  selectComments, // returns an array of comments
  (comments) => {
    console.log('calculating comments:', comments);
    return comments;
  }
);
selectEmailsFromComments({ comments: [{ id: 1 }] })
//this will log previous value because array length didn't change
console.log('memoized', selectEmailsFromComments({ comments: [{ id: 2 }] }))

关于reactjs - 如何使用重新选择和 typescript 创建自定义相等函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62480158/

相关文章:

reactjs - axios无法从本地json文件获取数据

javascript - 快速点击会产生太多请求

javascript - 如何将类方法分配给默认属性(即从静态范围引用非静态方法)

unit-testing - 如何为 Typescript 类型编写负面测试?

reactjs - react : declaration merging for react-table types doesn't work. 类型 'TableInstance' 上不存在属性

javascript - 如何解决state.set is not a function错误?

javascript - ReactJs:如何从路由器路径链接获取正确的变量?

javascript - 使用来自 Firebase 的数据时,卸载组件出现 setState 错误

reactjs - 监视 redux 调度方法

javascript - React redux 的 #applyMiddleware 如何通过返回 #createStore 而不是 store 来确保中间件仅应用一次?