edifice.use_async

edifice.use_async#

class edifice.use_async(fn_coroutine, dependencies)[source]#

Bases:

Asynchronous side-effect Hook inside a edifice.component() function.

Will create a new Task with the fn_coroutine coroutine.

The fn_coroutine will be called every time the dependencies change.

Example:

@component
def Asynchronous(self):
    myword, myword_set = use_state("")

    async def fetcher():
        try:
            x = await fetch_word_from_the_internet()
            myword_set(x)
        except asyncio.CancelledError:
            myword_set("Fetch word cancelled")
            raise

    _cancel_fetcher = use_async(fetcher, 0)
    Label(text=myword)

Cancellation#

The async fn_coroutine Task can be cancelled by Edifice. Edifice will call cancel() on the Task. See also Task Cancellation.

  1. If the dependencies change before the fn_coroutine Task completes, then the fn_coroutine Task will be cancelled and then the new fn_coroutine Task will be started after the old fn_coroutine Task completes.

  2. The use_async Hook returns a function which can be called to cancel the fn_coroutine Task manually. In the example above, the _cancel_fetcher() function can be called to cancel the fetcher.

  3. If the component is unmounted before the fn_coroutine Task completes, then the fn_coroutine Task will be cancelled.

Write your async fn_coroutine function in such a way that it cleans itself up after exceptions. If you catch a CancelledError then always re-raise it.

You may call a use_state() setter during a CancelledError exception. If the fn_coroutine Task was cancelled because the component is being unmounted, then the use_state() setter will have no effect.

Timers#

The use_async Hook is also useful for timers and animation.

Here is an example which shows how to run a timer in a component. The Harmonic Oscillator in Examples uses this technique:

is_playing, is_playing_set = use_state(False)
play_trigger, play_trigger_set = use_state(False)

async def play_tick():
    if is_playing:
        # Do the timer effect here
        # (timer effect code)

        # Then wait for 0.05 seconds and trigger another play_tick.
        await asyncio.sleep(0.05)
        play_trigger_set(lambda p: not p)

use_async(play_tick, (is_playing, play_trigger))

Button(
    text="pause" if is_playing else "play",
    on_click=lambda e: is_playing_set(lambda p: not p),
)
type fn_coroutine:

Callable[[], Coroutine[None, None, None]]

param fn_coroutine:

Async Coroutine function to be run as a Task.

type dependencies:

Any

param dependencies:

The fn_coroutine Task will be started when the dependencies are not __eq__ to the old dependencies.

rtype:

Callable[[], None]

returns:

A function which can be called to cancel the fn_coroutine Task manually.