Skip to content

Commit

Permalink
fix: unused selectors (#97)
Browse files Browse the repository at this point in the history
* add failing test for #96

* fix!!!!!!

* early return

* update CHANGELOG
  • Loading branch information
dai-shi authored May 2, 2024
1 parent 185d0ca commit 934efaa
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## [Unreleased]

### Changed
- fix: unused selectors #97

## [2.0.5] - 2024-01-15
### Changed
- fix: no extra calculation with nested memoized selectors #92
Expand Down
39 changes: 39 additions & 0 deletions __tests__/issue_96_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { memoize } from '../src/index';

describe('unused selectors (#96)', () => {
it('nested memoized selectors with primitive value access', () => {
type State = {
ids: string[];
entities: {
[id: string]: { name: string, array: string[] };
};
};
const state1: State = {
ids: ['1'],
entities: {
1: { name: 'first', array: [] },
},
};
const state2: State = {
ids: ['1'],
entities: {
1: { name: 'first', array: ['changed'] },
},
};
const selectAll = memoize((state: State) => state.ids.map((id) => state.entities[id]));
const selectAllNames = memoize((state: State) => (
state.ids.map((id) => state.entities[id]?.name)
));
const intermediateSelector = memoize((state: State) => {
selectAllNames(state);
return selectAll(state);
});
const finalSelector = memoize((state: State) => {
const combinedResult = intermediateSelector(state);
return combinedResult;
});
const result1 = finalSelector(state1);
const result2 = finalSelector(state2);
expect(result1).not.toEqual(result2);
});
});
13 changes: 10 additions & 3 deletions src/memoize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ type Used = {
};
type Affected = WeakMap<object, Used>;

const trackMemoOriginalObjSet = new WeakSet<object>();

const isObject = (x: unknown): x is object => typeof x === 'object' && x !== null;

const untrack = <T>(x: T, seen: Set<T>): T => {
if (!isObject(x)) return x;
const untrackedObj = getUntracked(x);
if (untrackedObj !== null) {
const originalObj = getUntracked(x);
if (originalObj !== null) {
trackMemo(x);
return untrackedObj;
trackMemoOriginalObjSet.add(originalObj);
return originalObj;
}
if (!seen.has(x)) {
seen.add(x);
Expand All @@ -47,6 +50,10 @@ const untrack = <T>(x: T, seen: Set<T>): T => {

const touchAffected = (dst: unknown, src: unknown, affected: Affected) => {
if (!isObject(dst) || !isObject(src)) return;
if (trackMemoOriginalObjSet.has(getUntracked(src) as never)) {
trackMemo(dst);
return;
}
const used = affected.get(getUntracked(src) || src);
if (!used) return;
used[HAS_KEY_PROPERTY]?.forEach((key) => {
Expand Down

0 comments on commit 934efaa

Please sign in to comment.