Skip to content

Commit

Permalink
feat: new dirty option for $computed
Browse files Browse the repository at this point in the history
  • Loading branch information
mihar-22 committed Jul 8, 2022
1 parent 945a4a1 commit 7ae2e6c
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 4 deletions.
16 changes: 13 additions & 3 deletions src/observables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,14 @@ export function isObservable<T>(fn: MaybeObservable<T>): fn is Observable<T> {
* console.log($c()); // logs 40
* ```
*/
export function $computed<T>(fn: () => T, opts?: { id?: string }): Observable<T> {
export function $computed<T>(
fn: () => T,
opts?: { id?: string; dirty?: (prev: T, next: T) => boolean },
): Observable<T> {
let currentValue;

const isDirty = opts?.dirty ?? notEqual;

const $computed: Observable<T> = () => {
if (__DEV__ && _computeStack.includes($computed)) {
const calls = _callStack.map((c) => c.id ?? '?').join(' --> ');
Expand All @@ -198,9 +203,14 @@ export function $computed<T>(fn: () => T, opts?: { id?: string }): Observable<T>
if (!$computed[DISPOSED] && $computed[DIRTY]) {
forEachChild($computed, $dispose);
emptyDisposal($computed);
currentValue = compute($computed, fn);

const nextValue = compute($computed, fn);
$computed[DIRTY] = false;
dirtyNode($computed);

if (isDirty(currentValue, nextValue)) {
currentValue = nextValue;
dirtyNode($computed);
}
}

return currentValue;
Expand Down
31 changes: 30 additions & 1 deletion tests/$computed.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { $computed, $observable, $tick } from '../src';
import { $computed, $effect, $observable, $tick } from '../src';

afterEach(() => $tick());

Expand Down Expand Up @@ -148,3 +148,32 @@ it('should discover new dependencies', async () => {
await $tick();
expect($c()).toBe(10);
});

it('should accept dirty option', async () => {
const $a = $observable(0);

const $b = $computed(() => $a(), {
// Skip odd numbers.
dirty: (prev, next) => prev + 1 !== next,
});

const effect = vi.fn();
$effect(() => {
$b();
effect();
});

expect($b()).toBe(0);
expect(effect).toHaveBeenCalledTimes(1);

$a.set(2);
await $tick();
expect($b()).toBe(2);
expect(effect).toHaveBeenCalledTimes(2);

// no-change
$a.set(3);
await $tick();
expect($b()).toBe(2);
expect(effect).toHaveBeenCalledTimes(2);
});

0 comments on commit 7ae2e6c

Please sign in to comment.