Skip to content

Commit 8218bba

Browse files
committed
feat(): add support for context.set and state.set (like React setState)
1 parent 38655e7 commit 8218bba

File tree

4 files changed

+58
-4
lines changed

4 files changed

+58
-4
lines changed

packages/runtime/src/internal/bindListeners.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ export function listenerFactory(
223223
case "context.replace":
224224
case "context.refresh":
225225
case "context.load":
226+
case "context.set":
226227
handleContextAction(
227228
event,
228229
method,
@@ -236,6 +237,7 @@ export function listenerFactory(
236237
case "state.update":
237238
case "state.refresh":
238239
case "state.load":
240+
case "state.set":
239241
handleTplStateAction(
240242
event,
241243
method,
@@ -687,7 +689,7 @@ function batchUpdate(
687689

688690
function handleContextAction(
689691
event: Event,
690-
method: "assign" | "replace",
692+
method: "assign" | "replace" | "refresh" | "load" | "set",
691693
args: unknown[] | undefined,
692694
batch: boolean,
693695
callback: BrickEventHandlerCallback | undefined,
@@ -717,7 +719,7 @@ function handleContextAction(
717719

718720
function handleTplStateAction(
719721
event: Event,
720-
method: "update" | "refresh" | "load",
722+
method: "update" | "refresh" | "load" | "set",
721723
args: unknown[] | undefined,
722724
batch: boolean,
723725
callback: BrickEventHandlerCallback | undefined,

packages/runtime/src/internal/data/DataStore.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,43 @@ describe("DataStore", () => {
378378
expect(mockCallRealTimeDataInspectHooks).toHaveBeenCalledTimes(2);
379379
});
380380

381+
test("context.set", async () => {
382+
setRealTimeDataInspectRoot({});
383+
const ctxStore = new DataStore("CTX");
384+
const runtimeContext = {
385+
ctxStore,
386+
} as Partial<RuntimeContext> as RuntimeContext;
387+
ctxStore.define(
388+
[
389+
{
390+
name: "primitive",
391+
value: "any",
392+
onChange: {
393+
action: "context.set",
394+
args: ["count", "<% (count) => count + 1 %>"],
395+
},
396+
},
397+
{
398+
name: "count",
399+
value: 0,
400+
},
401+
],
402+
runtimeContext
403+
);
404+
await ctxStore.waitForAll();
405+
expect(ctxStore.getValue("primitive")).toEqual("any");
406+
expect(ctxStore.getValue("count")).toBe(0);
407+
408+
const newValue = { amount: 42 };
409+
ctxStore.updateValue("primitive", newValue, "set");
410+
expect(ctxStore.getValue("primitive")).toEqual({ amount: 42 });
411+
expect(ctxStore.getValue("count")).toBe(1);
412+
413+
ctxStore.updateValue("primitive", newValue, "set");
414+
expect(ctxStore.getValue("primitive")).toEqual({ amount: 42 });
415+
expect(ctxStore.getValue("count")).toBe(1);
416+
});
417+
381418
test("state and onChange", async () => {
382419
jest.useFakeTimers();
383420
const tplStateStoreId = "tpl-state-1";

packages/runtime/src/internal/data/DataStore.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export class DataStore<T extends DataStoreType = "CTX"> {
193193
updateValue(
194194
name: string,
195195
value: unknown,
196-
method: "assign" | "replace" | "refresh" | "load",
196+
method: "assign" | "replace" | "refresh" | "load" | "set",
197197
callback?: BrickEventHandlerCallback,
198198
callbackRuntimeContext?: RuntimeContext
199199
): void {
@@ -276,7 +276,7 @@ export class DataStore<T extends DataStoreType = "CTX"> {
276276

277277
if (method === "replace") {
278278
item.value = value;
279-
} else {
279+
} else if (method === "assign") {
280280
if (isObject(item.value)) {
281281
Object.assign(item.value, value);
282282
} else {
@@ -286,6 +286,19 @@ export class DataStore<T extends DataStoreType = "CTX"> {
286286
);
287287
item.value = value;
288288
}
289+
} else {
290+
// method === "set"
291+
// `context.set` and `state.set` is similar to React's setState,
292+
// which accepts either a value or an updater function.
293+
// And if the new value is the same as the current one, do nothing.
294+
let nextValue = value;
295+
if (typeof value === "function") {
296+
nextValue = (value as (prevState: unknown) => unknown)(item.value);
297+
}
298+
if (Object.is(item.value, nextValue)) {
299+
return;
300+
}
301+
item.value = nextValue;
289302
}
290303

291304
if (this.batchUpdate) return;

packages/types/src/manifest.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,11 +980,13 @@ export interface BuiltinBrickEventHandler {
980980
| "context.replace"
981981
| "context.refresh"
982982
| "context.load"
983+
| "context.set"
983984

984985
// Update template state
985986
| "state.update"
986987
| "state.refresh"
987988
| "state.load"
989+
| "state.set"
988990

989991
// Find related tpl and dispatch event.
990992
| "tpl.dispatchEvent"

0 commit comments

Comments
 (0)