Skip to content

Commit

Permalink
Reading a computed makes it live
Browse files Browse the repository at this point in the history
  • Loading branch information
divdavem committed Sep 12, 2024
1 parent c6aa9ba commit 36ffafc
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 11 deletions.
16 changes: 11 additions & 5 deletions src/computed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ReactiveNode,
SIGNAL,
} from './graph.js';
import {beginEnsureLive} from './liveConsumer.js';

/**
* A computation, which derives a value from a declarative reactive expression.
Expand Down Expand Up @@ -48,11 +49,16 @@ export type ComputedGetter<T> = (() => T) & {
};

export function computedGet<T>(node: ComputedNode<T>) {
// Check if the value needs updating before returning it.
producerUpdateValueVersion(node);

// Record that someone looked at this signal.
producerAccessed(node);
const endEnsureLive = beginEnsureLive();
try {
// Check if the value needs updating before returning it.
producerUpdateValueVersion(node);

// Record that someone looked at this signal.
producerAccessed(node);
} finally {
endEnsureLive();
}

if (node.value === ERRORED) {
throw node.error;
Expand Down
25 changes: 25 additions & 0 deletions src/liveConsumer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
consumerBeforeComputation,
consumerDestroy,
getActiveConsumer,
REACTIVE_NODE,
setActiveConsumer,
} from './graph';

const noop = () => {};
export const beginEnsureLive = () => {
const activeConsumer = getActiveConsumer();
if (activeConsumer) {
return noop;
}

const liveConsumer = Object.create(REACTIVE_NODE);
liveConsumer.consumerIsAlwaysLive = true;
liveConsumer.consumerAllowSignalWrites = false;

setActiveConsumer(liveConsumer);
return () => {
setActiveConsumer(null);
consumerDestroy(liveConsumer);
};
};
16 changes: 10 additions & 6 deletions tests/behaviors/liveness.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ describe('liveness', () => {
[Signal.subtle.unwatched]: unwatchedSpy,
});
const computed = new Signal.Computed(() => state.get());
computed.get();
expect(watchedSpy).not.toBeCalled();
expect(unwatchedSpy).not.toBeCalled();
computed.get(); // reading a computed is considered watching and unwatching it
expect(watchedSpy).toHaveBeenCalledTimes(1);
expect(unwatchedSpy).toHaveBeenCalledTimes(1);
watchedSpy.mockClear();
unwatchedSpy.mockClear();

const w = new Signal.subtle.Watcher(() => {});
const w2 = new Signal.subtle.Watcher(() => {});
Expand Down Expand Up @@ -43,9 +45,11 @@ describe('liveness', () => {
[Signal.subtle.unwatched]: unwatchedSpy,
});

c.get();
expect(watchedSpy).not.toBeCalled();
expect(unwatchedSpy).not.toBeCalled();
c.get(); // reading a computed is considered watching and unwatching it
expect(watchedSpy).toHaveBeenCalledTimes(1);
expect(unwatchedSpy).toHaveBeenCalledTimes(1);
watchedSpy.mockClear();
unwatchedSpy.mockClear();

const w = new Signal.subtle.Watcher(() => {});
w.watch(c);
Expand Down

0 comments on commit 36ffafc

Please sign in to comment.