19
19
20
20
from typing_extensions import TypeAlias
21
21
22
- from reactpy .config import REACTPY_DEBUG_MODE
23
- from reactpy .core ._life_cycle_hook import (
24
- Context ,
25
- ContextProvider ,
26
- EffectInfo ,
27
- current_hook ,
28
- )
29
- from reactpy .core .types import Key , State
22
+ from reactpy .config import REACTPY_DEBUG_MODE , REACTPY_EFFECT_DEFAULT_STOP_TIMEOUT
23
+ from reactpy .core ._life_cycle_hook import EffectInfo , current_hook
24
+ from reactpy .core .types import Context , Key , State , VdomDict
30
25
from reactpy .utils import Ref
31
26
32
27
if not TYPE_CHECKING :
@@ -109,6 +104,7 @@ def dispatch(new: _Type | Callable[[_Type], _Type]) -> None:
109
104
def use_effect (
110
105
function : None = None ,
111
106
dependencies : Sequence [Any ] | ellipsis | None = ...,
107
+ stop_timeout : float = ...,
112
108
) -> Callable [[_EffectFunc ], None ]:
113
109
...
114
110
@@ -117,13 +113,15 @@ def use_effect(
117
113
def use_effect (
118
114
function : _EffectFunc ,
119
115
dependencies : Sequence [Any ] | ellipsis | None = ...,
116
+ stop_timeout : float = ...,
120
117
) -> None :
121
118
...
122
119
123
120
124
121
def use_effect (
125
122
function : _EffectFunc | None = None ,
126
123
dependencies : Sequence [Any ] | ellipsis | None = ...,
124
+ stop_timeout : float = REACTPY_EFFECT_DEFAULT_STOP_TIMEOUT .current ,
127
125
) -> Callable [[_EffectFunc ], None ] | None :
128
126
"""See the full :ref:`Use Effect` docs for details
129
127
@@ -135,6 +133,11 @@ def use_effect(
135
133
of any value in the given sequence changes (i.e. their :func:`id` is
136
134
different). By default these are inferred based on local variables that are
137
135
referenced by the given function.
136
+ stop_timeout:
137
+ The maximum amount of time to wait for the effect to cleanup after it has
138
+ been signaled to stop. If the timeout is reached, an exception will be
139
+ logged and the effect will be cancelled. This does not apply to synchronous
140
+ effects.
138
141
139
142
Returns:
140
143
If not function is provided, a decorator. Otherwise ``None``.
@@ -150,8 +153,7 @@ def add_effect(function: _EffectFunc) -> None:
150
153
async def create_effect_task () -> EffectInfo :
151
154
if effect_info .current is not None :
152
155
last_effect_info = effect_info .current
153
- last_effect_info .stop .set ()
154
- await last_effect_info .task
156
+ await last_effect_info .signal_stop (stop_timeout )
155
157
156
158
stop = asyncio .Event ()
157
159
info = EffectInfo (asyncio .create_task (effect (stop )), stop )
@@ -173,7 +175,8 @@ def _cast_async_effect(function: Callable[..., Any]) -> _AsyncEffectFunc:
173
175
return function
174
176
175
177
warnings .warn (
176
- 'Async effect functions should accept a "stop" asyncio.Event as their first argument' ,
178
+ 'Async effect functions should accept a "stop" asyncio.Event as their '
179
+ "first argument. This will be required in a future version of ReactPy." ,
177
180
stacklevel = 3 ,
178
181
)
179
182
@@ -249,8 +252,8 @@ def context(
249
252
* children : Any ,
250
253
value : _Type = default_value ,
251
254
key : Key | None = None ,
252
- ) -> ContextProvider [_Type ]:
253
- return ContextProvider (
255
+ ) -> _ContextProvider [_Type ]:
256
+ return _ContextProvider (
254
257
* children ,
255
258
value = value ,
256
259
key = key ,
@@ -280,7 +283,28 @@ def use_context(context: Context[_Type]) -> _Type:
280
283
raise TypeError (f"{ context } has no 'value' kwarg" ) # nocov
281
284
return cast (_Type , context .__kwdefaults__ ["value" ])
282
285
283
- return provider ._value
286
+ return provider .value
287
+
288
+
289
+ class _ContextProvider (Generic [_Type ]):
290
+ def __init__ (
291
+ self ,
292
+ * children : Any ,
293
+ value : _Type ,
294
+ key : Key | None ,
295
+ type : Context [_Type ],
296
+ ) -> None :
297
+ self .children = children
298
+ self .key = key
299
+ self .type = type
300
+ self .value = value
301
+
302
+ def render (self ) -> VdomDict :
303
+ current_hook ().set_context_provider (self )
304
+ return {"tagName" : "" , "children" : self .children }
305
+
306
+ def __repr__ (self ) -> str :
307
+ return f"{ type (self ).__name__ } ({ self .type } )"
284
308
285
309
286
310
_ActionType = TypeVar ("_ActionType" )
0 commit comments