From fdc5f599df59286cc59268d3b82b8fa36607e502 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Fri, 7 Jul 2023 17:19:26 -0700 Subject: [PATCH 1/2] Allow tasks to have an initial value --- .changeset/heavy-planets-obey.md | 5 ++++ packages/labs/task/src/task.ts | 17 ++++++++++++++ packages/labs/task/src/test/task_test.ts | 30 ++++++++++++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 .changeset/heavy-planets-obey.md diff --git a/.changeset/heavy-planets-obey.md b/.changeset/heavy-planets-obey.md new file mode 100644 index 0000000000..dd2ac02f72 --- /dev/null +++ b/.changeset/heavy-planets-obey.md @@ -0,0 +1,5 @@ +--- +'@lit-labs/task': minor +--- + +Allow tasks to have an initial value diff --git a/packages/labs/task/src/task.ts b/packages/labs/task/src/task.ts index 5e336a0da7..5e7f6f4322 100644 --- a/packages/labs/task/src/task.ts +++ b/packages/labs/task/src/task.ts @@ -49,6 +49,16 @@ export interface TaskConfig, R> { task: TaskFunction; args?: ArgsFunction; autoRun?: boolean; + + /** + * If initialValue is provided, the task is initialized to the COMPLETE + * status and the value is set to initialData. + * + * Initial args should be coherent with the initialValue, since they are + * assumed to be the args that would produce that value. When autoRun is + * `true` the task will not auto-run again until the args change. + */ + initialValue?: R; onComplete?: (value: R) => unknown; onError?: (error: unknown) => unknown; } @@ -185,6 +195,13 @@ export class Task< if (taskConfig.autoRun !== undefined) { this.autoRun = taskConfig.autoRun; } + // Providing initialValue puts the task in COMPLETE state and stores the + // args immediately so it only runs when they change again. + if ('initialValue' in taskConfig) { + this._value = taskConfig.initialValue; + this.status = TaskStatus.COMPLETE; + this._previousArgs = this._getArgs?.(); + } } hostUpdated() { diff --git a/packages/labs/task/src/test/task_test.ts b/packages/labs/task/src/test/task_test.ts index e086af85ac..085e49166c 100644 --- a/packages/labs/task/src/test/task_test.ts +++ b/packages/labs/task/src/test/task_test.ts @@ -225,6 +225,36 @@ suite('Task', () => { assert.equal(el.taskValue, `a1,b1`); }); + test('tasks can have initialValue', async () => { + // The test helpers make it hard to write proper args callbacks + // `args: () => [this.a, this.b]` would work, but `[el.a]` doesn't + // since `el` isn't initialized yet. This little hack works: + let initializing = true; + const el = getTestElement({ + initialValue: 'initial', + args: () => [initializing ? 'a' : el.a, initializing ? 'b' : el.b], + }); + initializing = false; + await renderElement(el); + assert.equal(el.task.status, TaskStatus.COMPLETE); + assert.equal(el.task.value, 'initial'); + assert.equal(el.taskValue, 'initial'); + + // The task is complete, so waiting for it shouldn't change anything + await tasksUpdateComplete(); + assert.equal(el.task.status, TaskStatus.COMPLETE); + assert.equal(el.task.value, 'initial'); + + // The task still reruns when arguments change + el.a = 'a1'; + await tasksUpdateComplete(); + assert.equal(el.task.status, TaskStatus.PENDING); + el.resolveTask(); + await tasksUpdateComplete(); + assert.equal(el.task.status, TaskStatus.COMPLETE); + assert.equal(el.taskValue, `a1,b`); + }); + test('task error is not reset on rerun', async () => { const el = getTestElement({args: () => [el.a, el.b]}); await renderElement(el); From 8487dfb5dc59e32a4e5e541db84f1a5e1182a3e2 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Fri, 7 Jul 2023 19:05:07 -0700 Subject: [PATCH 2/2] Add an assertion --- packages/labs/task/src/test/task_test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/labs/task/src/test/task_test.ts b/packages/labs/task/src/test/task_test.ts index 085e49166c..bce98225a6 100644 --- a/packages/labs/task/src/test/task_test.ts +++ b/packages/labs/task/src/test/task_test.ts @@ -245,6 +245,12 @@ suite('Task', () => { assert.equal(el.task.status, TaskStatus.COMPLETE); assert.equal(el.task.value, 'initial'); + // An element update (which checks args again) should not cause a rerun + el.requestUpdate(); + await tasksUpdateComplete(); + assert.equal(el.task.status, TaskStatus.COMPLETE); + assert.equal(el.task.value, 'initial'); + // The task still reruns when arguments change el.a = 'a1'; await tasksUpdateComplete();