Skip to content

Commit 64c9b63

Browse files
committed
Add use_async_effect shielding option
1 parent 613b256 commit 64c9b63

1 file changed

Lines changed: 12 additions & 3 deletions

File tree

src/reactpy/core/hooks.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,19 +180,22 @@ async def effect(stop: asyncio.Event) -> None:
180180
def use_async_effect(
181181
function: None = None,
182182
dependencies: Sequence[Any] | ellipsis | None = ...,
183+
shield: bool = False,
183184
) -> Callable[[_EffectApplyFunc], None]: ...
184185

185186

186187
@overload
187188
def use_async_effect(
188189
function: _AsyncEffectFunc,
189190
dependencies: Sequence[Any] | ellipsis | None = ...,
191+
shield: bool = False,
190192
) -> None: ...
191193

192194

193195
def use_async_effect(
194196
function: _AsyncEffectFunc | None = None,
195197
dependencies: Sequence[Any] | ellipsis | None = ...,
198+
shield: bool = False,
196199
) -> Callable[[_AsyncEffectFunc], None] | None:
197200
"""
198201
A hook that manages an asynchronous side effect in a React-like component.
@@ -209,6 +212,11 @@ def use_async_effect(
209212
of any value in the given sequence changes (i.e. their :func:`id` is
210213
different). By default these are inferred based on local variables that are
211214
referenced by the given function.
215+
shield:
216+
If ``True``, the effect will not be cancelled when the hook is running clean-up.
217+
This can be useful if you want to ensure that the effect runs to completion even if the
218+
component is unmounted while the effect is still running (e.g. a database query).
219+
However, use this option with caution as it can lead to memory leaks.
212220
213221
Returns:
214222
If not function is provided, a decorator. Otherwise ``None``.
@@ -255,9 +263,10 @@ async def effect(stop: asyncio.Event) -> None:
255263
await stop.wait()
256264
# Stop signal came first - cancel the effect task
257265
else:
258-
task.cancel()
259-
with contextlib.suppress(asyncio.CancelledError):
260-
await task
266+
# Prevent task cancellation if the user enabled shielding
267+
if not shield:
268+
task.cancel()
269+
await asyncio.shield(task)
261270

262271
# Run the clean-up function when the effect is stopped,
263272
# if it hasn't been run already by a new effect

0 commit comments

Comments
 (0)