使用相同的输入分别调用 createSelector 会创建多个记忆结果吗?

Do separate calls to createSelector with same inputs create multiple memoized results?

当我们最初设置我们的新 React 项目并决定使用 Re-Select 来记忆我们的选择器时,选择了一种模式来围绕对 create[= 的调用创建包装函数40=]or() 以便根据单独的组件上下文潜在地参数化一些记忆...

然而,随着时间的推移,这已成为例外而不是规则,现在我们团队中的一些开发人员正在反复考虑是否多次调用 createSelector 具有相同的输入导致结果数据的多个单独的 memoized 副本,或者如果它们都指向相同的结果。

示例:

const _getFoos = (state) => state.foos;
const _mapFoosToItems = (foos) => foos.map(createFooItem);

export const selectFooItems = () => {
  return createSelector(_getFoos, _mapFoosToItems);
}

// Component1.tsx
const mapStateToProps = {
 fooItems: selectFooItems()
}

// Component2.tsx
const mapStateToProps = {
 fooItems: selectFooItems()
}

在上面的示例中,我们是否创建了 2 个完全独立的记忆化选择器,它们具有重复但独立的记忆化结果?还是 createSelector 以某种方式自动知道这两个选择器是相同的,因为输入选择器功能和输出是相同的?

在上面的示例中,由于我们没有特定于上下文的参数,是否最好删除围绕 createSelect 或 的匿名包装器并仅设置 selectFooItems直接到createSelector结果

示例:

export const selectFooitems = createSelector(_getFoos, _mapFoosToItems);

// Component1.tsx
const mapStateToProps = {
 fooItems: selectFooItems
}

// Component2.tsx
const mapStateToProps = {
 fooItems: selectFooItems
}

你的假设是准确的。

第一种情况,每次调用 selectFooItems 都会创建一个新的选择器,并带有自己的记忆。因此,即使两者都使用相同的参数调用,两者也将完全执行,因为没有共享任何内容。

在您的第二个示例中,由于如果使用相同的参数调用第二种情况,则两者共享相同的选择器,因此记忆结果将是 returned。

Here is a basic demo of this functionality:

import { createSelector } from "reselect";

const createFooItem = foo => ({ foo });
const _getFoos = state => state.foos;
const _mapFoosToItems = foos => {
  console.log("_mapFoosToItems invoked");
  return foos.map(createFooItem);
};

export const selectFooItems = () => {
  return createSelector(
    _getFoos,
    _mapFoosToItems
  );
};

const mapStateToProps1 = {
  fooItems: selectFooItems()
};

const mapStateToProps2 = {
  fooItems: selectFooItems()
};

const foos = [1, 2];

// These next two console.log's will produce:
//  _mapFoosToItems invoked
//  [{ foo: 1 }, { foo: 2 }]
//  _mapFoosToItems invoked
//  [{ foo: 1 }, { foo: 2 }]
//  Equal: false

const result1 = mapStateToProps1.fooItems({ foos });
console.log(result1);
const result2 = mapStateToProps2.fooItems({ foos });
console.log(result2);
console.log(`Equal: ${result1 === result2}`);

const shared = createSelector(
  _getFoos,
  _mapFoosToItems
);

const mapStateToProps3 = {
  fooItems: shared
};

const mapStateToProps4 = {
  fooItems: shared
};

// These next two console.log's will produce:
//  _mapFoosToItems invoked
//  [{ foo: 1 }, { foo: 2 }]
//  [{ foo: 1 }, { foo: 2 }]
//  Equal: true

const result3 = mapStateToProps3.fooItems({ foos });
console.log(result3);
const result4 = mapStateToProps4.fooItems({ foos });
console.log(result4);
console.log(`Equal: ${result3 === result4}`);

您还可以通过相等性检查看到存储的结果正在 returned。由于 _mapFoosToItems 方法 return 是 .map 的结果,每次执行该方法时,它都会 return 一个新的数组实例。所以 result3result4 可能相同的唯一方法 (===) 是因为记忆结果是 returned.