vueuse icon indicating copy to clipboard operation
vueuse copied to clipboard

`useAsyncState` | execute with the same type as the original function

Open davidglezz opened this issue 11 months ago • 4 comments

Clear and concise description of the problem

Regarding useAsyncState

I expect the execute function to have the same type as the original function, so it makes migrations and usage much easier.

Currently, we have to change the arguments to remove the 0 delay. Example:

<Component @click="doSomething" />
<script setup>
const { execute } = useAsyncState(originalDoSomething), null)
const doSomething = (...args) => execute(0, ...args) // converting execute to the original shape.
</script>

Suggested solution

  export interface UseAsyncStateReturnBase<Data, Params extends any[], Shallow extends boolean> {
    state: Shallow extends true ? Ref<Data> : Ref<UnwrapRef<Data>>
    isReady: Ref<boolean>
    isLoading: Ref<boolean>
    error: Ref<unknown>
-    execute: (delay?: number, ...args: Params) => Promise<Data>
+    execute: (...args: Params) => Promise<Data>
+    executeWithDelay: (delay?: number, ...args: Params) => Promise<Data>
  }

Example:

<Component @click="doSomething" />
<script setup>
const { execute: doSomething } = useAsyncState(originalDoSomething), null)
</script>

Alternative

To avoid breaking changes we could add the run, executeNow or executeImmediate function, but I think that its better default execute (now) and executeWithDelay/executeDelayed/executeAfter or other name to include options.

Additional context

No response

Validations

davidglezz avatar Feb 13 '25 08:02 davidglezz

I think it might be executeImmediately or executeNow to maintain back compatibility.

EvgenyWas avatar Feb 13 '25 18:02 EvgenyWas

I also prefer the returned execute with the same param type as the input one. delay might be unnecessary because it can be done by users, something like:

setTimeout(() => {
  execute();
}, delay);

hoishing-lam avatar Feb 25 '25 07:02 hoishing-lam

I'd like to add my vote for this change. Just wasted +60 minutes by trying to investigate how did I manage to put the parameters in weird/wrong order. After a while of head banging I navigated to source code here. It took a moment at that point also to understand what the underlying issue was.

I'm somewhat accustomed to digging through source codes of libs, but I can easily see this biting pretty painfully for the non-accustomed ones...

The pattern I was using looks something like this:

const { execute: fetchData, state: result } = useAsyncState(
  async (inputParam, currentRole) => {
    // some logic
    return await doTheFetching(inputParam, currentRole)
  },
  undefined
  { immediate: false } // will be done by watchEffect
)

watchEffect(() => {
  // wtf params in doTheFetching all wrong, did I put these to wrong order
  fetchData(someRef.value, currentRole.value)
  // ... after +60mins + source code reverse engineering and finding this issue
  fetchData(0, someRef.value, currentRole.value)
})

Snurppa avatar Apr 16 '25 17:04 Snurppa

To keep backward compatibility, I just added executeNow method in https://github.com/vueuse/vueuse/pull/4716

davidglezz avatar Apr 18 '25 10:04 davidglezz