edifice.use_async#
- edifice.use_async(fn_coroutine, dependencies)[source]#
Asynchronous side-effect Hook inside a
@component
function.Will create a new Task with the
fn_coroutine
coroutine.The
fn_coroutine
will be called every time thedependencies
change. Only onefn_coroutine
will be allowed to run at a time.@component def WordDefinition(self, word:str): definition, definition_set = use_state("") async def fetcher(): try: definition_set("Fetch definition pending") x = await fetch_definition_from_the_internet(word) definition_set(x) except asyncio.CancelledError: definition_set("Fetch definition cancelled") raise except BaseException: defintion_set("Fetch definition failed") cancel_fetcher = use_async(fetcher, word) with VBoxView(): Label(text=word) Label(text=definition) Button(text="Cancel fetch", on_click=lambda _:cancel_fetcher())
Cancellation#
The async
fn_coroutine
Task can be cancelled by Edifice. Edifice will call cancel() on the Task. See also Task Cancellation.If the
dependencies
change before thefn_coroutine
Task completes, then thefn_coroutine
Task will be cancelled and then the newfn_coroutine
Task will be started after the oldfn_coroutine
Task completes.The
use_async
Hook returns a function which can be called to cancel thefn_coroutine
Task manually. In the example above, the_cancel_fetcher()
function can be called to cancel the fetcher.If the component is unmounted before the
fn_coroutine
Task completes, then thefn_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 aCancelledError
then always re-raise it.You may call a
use_state()
setter during aCancelledError
exception. If thefn_coroutine
Task was cancelled because the component is being unmounted, then theuse_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 thedependencies
are not__eq__
to the olddependencies
.- rtype:
Callable
[[],None
]- returns:
A function which can be called to cancel the
fn_coroutine
Task manually.