|
14 | 14 | NamedTuple, |
15 | 15 | List, |
16 | 16 | overload, |
| 17 | + cast, |
17 | 18 | ) |
18 | 19 | from typing_extensions import Protocol |
19 | 20 |
|
@@ -87,7 +88,9 @@ def dispatch( |
87 | 88 |
|
88 | 89 |
|
89 | 90 | _EffectCleanFunc = Callable[[], None] |
90 | | -_EffectApplyFunc = Callable[[], Optional[_EffectCleanFunc]] |
| 91 | +_SyncEffectFunc = Callable[[], Optional[_EffectCleanFunc]] |
| 92 | +_AsyncEffectFunc = Callable[[], Awaitable[Optional[_EffectCleanFunc]]] |
| 93 | +_EffectApplyFunc = Union[_SyncEffectFunc, _AsyncEffectFunc] |
91 | 94 |
|
92 | 95 |
|
93 | 96 | @overload |
@@ -124,10 +127,32 @@ def use_effect( |
124 | 127 | memoize = use_memo(args=args) |
125 | 128 |
|
126 | 129 | def add_effect(function: _EffectApplyFunc) -> None: |
| 130 | + |
| 131 | + if not asyncio.iscoroutinefunction(function): |
| 132 | + sync_function = cast(_SyncEffectFunc, function) |
| 133 | + else: |
| 134 | + |
| 135 | + async_function = cast(_AsyncEffectFunc, function) |
| 136 | + |
| 137 | + def sync_function() -> Optional[_EffectCleanFunc]: |
| 138 | + future = asyncio.ensure_future(async_function()) |
| 139 | + |
| 140 | + def clean_future() -> None: |
| 141 | + try: |
| 142 | + clean = future.result() |
| 143 | + except asyncio.InvalidStateError: |
| 144 | + future.cancel() |
| 145 | + else: |
| 146 | + if clean is not None: |
| 147 | + clean() |
| 148 | + |
| 149 | + return clean_future |
| 150 | + |
127 | 151 | def effect() -> None: |
128 | | - clean = function() |
| 152 | + clean = sync_function() |
129 | 153 | if clean is not None: |
130 | 154 | hook.add_effect("will_render will_unmount", clean) |
| 155 | + return None |
131 | 156 |
|
132 | 157 | return memoize(lambda: hook.add_effect("did_render", effect)) |
133 | 158 |
|
@@ -313,53 +338,6 @@ def use_ref(initial_value: _StateType) -> Ref[_StateType]: |
313 | 338 | return _use_const(lambda: Ref(initial_value)) |
314 | 339 |
|
315 | 340 |
|
316 | | -_AsyncCleanFunc = Callable[[], None] |
317 | | -_AsyncApplyFunc = Callable[[], Awaitable[Optional[_EffectCleanFunc]]] |
318 | | - |
319 | | - |
320 | | -@overload |
321 | | -def use_async( |
322 | | - function: None = None, args: Optional[Sequence[Any]] = None |
323 | | -) -> Callable[[_AsyncApplyFunc], None]: |
324 | | - ... |
325 | | - |
326 | | - |
327 | | -@overload |
328 | | -def use_async(function: _AsyncApplyFunc, args: Optional[Sequence[Any]] = None) -> None: |
329 | | - ... |
330 | | - |
331 | | - |
332 | | -def use_async( |
333 | | - function: Optional[_AsyncApplyFunc] = None, |
334 | | - args: Optional[Sequence[Any]] = None, |
335 | | -) -> Optional[Callable[[_AsyncApplyFunc], None]]: |
336 | | - effect = use_effect(args=args) |
337 | | - |
338 | | - def add_asyc_effect(function: _AsyncApplyFunc) -> None: |
339 | | - def create_future() -> Callable[[], None]: |
340 | | - future = asyncio.ensure_future(function()) |
341 | | - |
342 | | - def cleanup_future() -> None: |
343 | | - try: |
344 | | - cleanup = future.result() |
345 | | - except asyncio.InvalidStateError: |
346 | | - future.cancel() |
347 | | - else: |
348 | | - if cleanup is not None: |
349 | | - cleanup() |
350 | | - |
351 | | - return cleanup_future |
352 | | - |
353 | | - effect(create_future) |
354 | | - return None |
355 | | - |
356 | | - if function is not None: |
357 | | - add_asyc_effect(function) |
358 | | - return None |
359 | | - else: |
360 | | - return add_asyc_effect |
361 | | - |
362 | | - |
363 | 341 | def _use_const(function: Callable[[], _StateType]) -> _StateType: |
364 | 342 | return current_hook().use_state(function) |
365 | 343 |
|
|
0 commit comments