diff --git a/.changeset/afraid-lions-nail.md b/.changeset/afraid-lions-nail.md new file mode 100644 index 000000000..5db0e8c7f --- /dev/null +++ b/.changeset/afraid-lions-nail.md @@ -0,0 +1,5 @@ +--- +'@quilted/async': patch +--- + +Add control for handling `AsyncAction.value` in error and revalidation scenarios diff --git a/packages/async/source/AsyncAction.ts b/packages/async/source/AsyncAction.ts index 558162560..a69f00f75 100644 --- a/packages/async/source/AsyncAction.ts +++ b/packages/async/source/AsyncAction.ts @@ -28,7 +28,19 @@ export class AsyncAction { } get value() { - return this.latest?.value ?? this.resolved?.value; + const running = this.running; + const runningValue = running?.value; + if (runningValue !== undefined) return runningValue; + + if (!this.#staleWhileRevalidate && running) { + return undefined; + } + + if (!this.#staleIfError && this.finished?.error) { + return undefined; + } + + return this.resolved?.value; } get data() { @@ -108,11 +120,16 @@ export class AsyncAction { lastInput?: Input, ) => boolean; + readonly #staleIfError: boolean; + readonly #staleWhileRevalidate: boolean; + constructor( fetchFunction: AsyncActionFunction, { cached, hasChanged = defaultHasChanged, + staleIfError = true, + staleWhileRevalidate = true, }: { cached?: AsyncActionRunCache; hasChanged?( @@ -120,6 +137,8 @@ export class AsyncAction { input?: Input, lastInput?: Input, ): boolean; + staleIfError?: boolean; + staleWhileRevalidate?: boolean; } = {}, ) { this.function = fetchFunction; @@ -128,6 +147,8 @@ export class AsyncAction { finally: this.#finalizeAction, }); this.#hasChanged = hasChanged; + this.#staleIfError = staleIfError; + this.#staleWhileRevalidate = staleWhileRevalidate; } run = (