如果输入选择器未能通过严格的相等检查,标准的重新选择选择器会使它的内存值无效并重新计算它:
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/