Skip to content

Commit

Permalink
Refactor some node activation to a separate function so that persiste…
Browse files Browse the repository at this point in the history
…nce can override it
  • Loading branch information
jmeistrich committed Oct 23, 2023
1 parent cbf98e7 commit 41b1dda
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 50 deletions.
125 changes: 76 additions & 49 deletions src/ObservableObject.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { beginBatch, endBatch, notify } from './batching';
import { batch, beginBatch, endBatch, notify } from './batching';
import { createObservable } from './createObservable';
import {
checkActivate,
Expand Down Expand Up @@ -831,39 +831,19 @@ export function peek(node: NodeValue) {
}

function activateNodeFunction(node: NodeValue) {
let dispose: () => void;
let subscribed = false;
let isSetting = false;
let setter: (value: any) => void;
let update: (value: any) => void;
let subscriber: (params: { update: any }) => void;
// The onSet function handles the observable being set
// and forwards the set elsewhere
const onSet: ComputedParams['onSet'] = (setter) => {
const doSet = (params: ListenerParamsRemote) => {
// Don't call the set if this is the first value coming in
if (params.changes.length > 1 || !isFunction(params.changes[0].prevAtPath)) {
isSetting = true;
try {
params.isRemote = globalState.isLoadingRemote$.peek();
setter(params);
} finally {
isSetting = false;
}
}
};
dispose?.();
dispose = onChange(node, doSet as any, { immediate: true });
const onSet: ComputedParams['onSet'] = (setterParam) => {
setter = setterParam;
};
// The subscribe function runs a function that listens to
// a data source and sends updates into the observable
const subscribe: ComputedParams['subscribe'] = (fn) => {
if (!subscribed) {
subscribed = true;
fn({
update: ({ value }) => {
globalState.onChangeRemote(() => {
set(node, value);
});
},
});
if (!subscriber) {
subscriber = fn;
}
};
// The proxy function simply marks the node as a proxy with this function
Expand All @@ -872,17 +852,7 @@ function activateNodeFunction(node: NodeValue) {
const proxy: ComputedProxyParams['proxy'] = (fn) => {
node.proxyFn2 = fn;
};
if (!node.state) {
node.state = createObservable<ObservableState>(
{
isLoaded: false,
},
false,
extractPromise,
getProxy,
) as ObservableObject<ObservableState>;
}
const { isLoaded } = node.state;

let prevTarget$: ObservableObject<any>;
let curTarget$: ObservableObject<any>;
let wasPromise: boolean;
Expand Down Expand Up @@ -915,27 +885,84 @@ function activateNodeFunction(node: NodeValue) {
value = value.get();
}

if (isPromise(value)) {
const isProm = isPromise(value);

if (!node.state) {
update = activateBase(node, value, setter, subscriber).update;
}
if (isProm) {
wasPromise = true;
extractPromise(node, value);
value = undefined;
}
return value;
},
({ value }) => {
if (!isSetting) {
const doSet = () => {
set(node, value);
isLoaded.set(true);
};
if (!globalState.isLoadingRemote$.peek()) {
if (wasPromise) {
wasPromise = false;
globalState.onChangeRemote(doSet);
update({ value });
} else {
doSet();
set(node, value);
}
node.state!.isLoaded.set(true);
}
},
{ immediate: true, fromComputed: true },
);
}

export function activateBase(
node: NodeValue,
newValue: any,
setter: (value: any) => void,
subscriber: (params: { update: any }) => void,
): { update: any } {
let isSetting = false;
if (!node.state) {
node.state = createObservable<ObservableState>(
{
isLoaded: false,
},
false,
extractPromise,
getProxy,
) as ObservableObject<ObservableState>;
}
if (setter) {
const doSet = (params: ListenerParamsRemote) => {
// Don't call the set if this is the first value coming in
if (!isSetting) {
if (params.changes.length > 1 || !isFunction(params.changes[0].prevAtPath)) {
isSetting = true;
params.isRemote = globalState.isLoadingRemote$.peek();
batch(
() => setter(params),
() => {
isSetting = false;
},
);
}
}
};

onChange(node, doSet as any, { immediate: true });
}

const update = ({ value }: { value: any }) => {
if (!isSetting) {
globalState.onChangeRemote(() => {
set(node, value);
});
}
};

const isProm = isPromise(newValue);
if (isProm) {
extractPromise(node, newValue);
}

if (subscriber) {
subscriber({ update });
}

return { update };
}
5 changes: 4 additions & 1 deletion tests/computed.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,11 @@ describe('Two way Computed', () => {
const obs = observable({ test: false, test2: false });
const comp = observable(({ onSet }: ComputedParams) => {
onSet(({ value }) => {
obs.test.set(value) && obs.test2.set(value);
obs.test.set(value);
obs.test2.set(value);
});
const a = obs.test.get();

Check warning on line 164 in tests/computed.test.ts

View workflow job for this annotation

GitHub Actions / Lint

'a' is assigned a value but never used
const b = obs.test2.get();

Check warning on line 165 in tests/computed.test.ts

View workflow job for this annotation

GitHub Actions / Lint

'b' is assigned a value but never used
return obs.test.get() && obs.test2.get();
});
expect(comp.get()).toEqual(false);
Expand Down

0 comments on commit 41b1dda

Please sign in to comment.