如何使用reselect和Typescript创建自定义相等函数? [英] How to create a custom equality function with reselect and Typescript?

查看:165
本文介绍了如何使用reselect和Typescript创建自定义相等函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果输入选择器未通过严格的相等性检查,则标准的重新选择选择器将使其记忆值无效并重新计算:

A standard reselect selector invalidates its memoized value and recomputes it if the input selectors fail a strict equality check:

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

由于注释是数组,而不是原始值,并且redux reducers倾向于创建新的状态以避免副作用,因此上述内容似乎从未真正记住,因为selectComments返回的注释数组将始终具有另一种参考.

Since the comments are an array and not a primitive value, and redux reducers tend to create a new piece of state to avoid side effects, the above seems to never actually memoize because the comments array returned by selectComments will always have a different reference.

要解决此问题,可以创建自定义选择器创建器 ,例如引入浅层相等性检查:

To resolve this, one can create a custom selector creator, e.g. to introduce shallow equality checks:

const createShallowEqualSelector = createSelectorCreator(
  defaultMemoize,
  shallowEqual
)

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

如果评论确实是简单的对象,并且我们希望在评论的任何道具发生更改时都重新计算电子邮件,则可以使用此功能.

This works if the comments indeed are simple objects and we want to recompute the emails whenever any of the comments' props changed.

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

But what if we only want to recompute the emails if e.g. the number of comments changed? How could we implement a custom equality check? I would expect the following to work:

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错误:

However this returns the following Typescript error for defaultMemoize:

(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相等函数,如何解决此类型错误?

How would I resolve this type error for a custom reselect createSelector equality function?

推荐答案

以下内容对我有用,但我不确定这是否是最佳方法.

The following worked for me but I'm not sure if it's the best way.

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 }] }))

这篇关于如何使用reselect和Typescript创建自定义相等函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆