Skip to content

Commit

Permalink
fix: Static props prevents selectors recall [2] (#102)
Browse files Browse the repository at this point in the history
* add failing test

* simplify the test

* minor adjustment

* fix it, but not super confident

* update CHANGELOG
  • Loading branch information
dai-shi authored Jul 12, 2024
1 parent 534afa9 commit ceae1ec
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 11 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Changed

- fix: Static props prevents selectors recall #101
- fix: Static props prevents selectors recall [2] #102

## [3.0.0] - 2024-05-02

Expand Down
21 changes: 12 additions & 9 deletions src/memoize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@ type Used = {
};
type Affected = WeakMap<object, Used>;

const trackMemoOriginalObjSet = new WeakSet<object>();
const trackMemoUntrackedObjSet = new WeakSet<object>();

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

const untrack = <T>(x: T, seen: WeakSet<object>): T => {
if (!isObject(x)) return x;
const originalObj = getUntracked(x);
if (originalObj !== null) {
const untrackedObj = getUntracked(x);
if (untrackedObj) {
trackMemo(x);
trackMemoOriginalObjSet.add(originalObj);
return originalObj;
trackMemoUntrackedObjSet.add(untrackedObj);
return untrackedObj;
}
if (!seen.has(x)) {
seen.add(x);
Expand All @@ -46,11 +46,14 @@ const untrack = <T>(x: T, seen: WeakSet<object>): T => {

const touchAffected = (dst: unknown, src: unknown, affected: Affected) => {
if (!isObject(dst) || !isObject(src)) return;
if (trackMemoOriginalObjSet.has(getUntracked(src) as never)) {
trackMemo(dst);
const untrackedObj = getUntracked(src);
const used = affected.get(untrackedObj || src);
if (!used) {
if (trackMemoUntrackedObjSet.has(untrackedObj as never)) {
trackMemo(dst);
}
return;
}
const used = affected.get(getUntracked(src) || src);
if (!used) return;
used[HAS_KEY_PROPERTY]?.forEach((key) => {
Reflect.has(dst, key);
});
Expand Down
49 changes: 47 additions & 2 deletions tests/issue_100.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ describe('Static props prevents selectors recall (#100)', () => {
},
};

const selectAllBooks = memoize((state: State) => Object.values(state));
const selectBook1 = memoize((state: State) => state.book1);

const selectPriceString = memoize(
(state: State) => state.book1.priceString,
Expand All @@ -36,7 +36,52 @@ describe('Static props prevents selectors recall (#100)', () => {
return priceString;
});

selectAllBooks(state1);
selectBook1(state1);

expect(selectAdjustedPriceString(state1)).toBe('10');
expect(selectAdjustedPriceString(state2)).toBe('20');
});

it('case 2', () => {
type State = {
book1: {
staticProp: string;
priceString: string;
};
};

const state1: State = {
book1: {
staticProp: '5',
priceString: '10',
},
};

const state2: State = {
book1: {
staticProp: '5',
priceString: '20',
},
};

const selectBook1 = memoize((state: State) => state.book1);

const selectPriceString = memoize(
(state: State) => state.book1.priceString,
);

const selectAdjustedPriceString = memoize((state: State) => {
const priceString = selectPriceString(state);
state.book1.staticProp; // touch the prop
return priceString;
});

const selectMemoizedPriceString = memoize((state: State) =>
selectPriceString(state),
);

selectBook1(state1);
selectMemoizedPriceString(state1);

expect(selectAdjustedPriceString(state1)).toBe('10');
expect(selectAdjustedPriceString(state2)).toBe('20');
Expand Down

0 comments on commit ceae1ec

Please sign in to comment.