如何使用reselect和Typescript创建自定义相等函数? [英] How to create a custom equality function with reselect and 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屋!