30
30
31
31
32
32
__all__ = [
33
- "use_state " ,
33
+ "use_callback " ,
34
34
"use_effect" ,
35
+ "use_memo" ,
35
36
"use_reducer" ,
36
- "use_callback" ,
37
37
"use_ref" ,
38
- "use_memo " ,
38
+ "use_state " ,
39
39
]
40
40
41
41
logger = getLogger (__name__ )
@@ -110,15 +110,15 @@ def use_effect(
110
110
111
111
@overload
112
112
def use_effect (
113
- function : _EffectApplyFunc ,
113
+ function : _SyncEffectFunc ,
114
114
dependencies : Sequence [Any ] | ellipsis | None = ...,
115
115
) -> None : ...
116
116
117
117
118
118
def use_effect (
119
- function : _EffectApplyFunc | None = None ,
119
+ function : _SyncEffectFunc | None = None ,
120
120
dependencies : Sequence [Any ] | ellipsis | None = ...,
121
- ) -> Callable [[_EffectApplyFunc ], None ] | None :
121
+ ) -> Callable [[_SyncEffectFunc ], None ] | None :
122
122
"""See the full :ref:`Use Effect` docs for details
123
123
124
124
Parameters:
@@ -134,37 +134,87 @@ def use_effect(
134
134
If not function is provided, a decorator. Otherwise ``None``.
135
135
"""
136
136
hook = current_hook ()
137
-
138
137
dependencies = _try_to_infer_closure_values (function , dependencies )
139
138
memoize = use_memo (dependencies = dependencies )
140
139
last_clean_callback : Ref [_EffectCleanFunc | None ] = use_ref (None )
141
140
142
- def add_effect (function : _EffectApplyFunc ) -> None :
143
- if not asyncio .iscoroutinefunction (function ):
144
- sync_function = cast (_SyncEffectFunc , function )
145
- else :
146
- async_function = cast (_AsyncEffectFunc , function )
141
+ def add_effect (function : _SyncEffectFunc ) -> None :
142
+ async def effect (stop : asyncio .Event ) -> None :
143
+ if last_clean_callback .current is not None :
144
+ last_clean_callback .current ()
145
+ last_clean_callback .current = None
146
+ clean = last_clean_callback .current = function ()
147
+ await stop .wait ()
148
+ if clean is not None :
149
+ clean ()
150
+
151
+ return memoize (lambda : hook .add_effect (effect ))
152
+
153
+ if function is not None :
154
+ add_effect (function )
155
+ return None
156
+
157
+ return add_effect
158
+
159
+
160
+ @overload
161
+ def use_async_effect (
162
+ function : None = None ,
163
+ dependencies : Sequence [Any ] | ellipsis | None = ...,
164
+ ) -> Callable [[_EffectApplyFunc ], None ]: ...
147
165
148
- def sync_function () -> _EffectCleanFunc | None :
149
- task = asyncio .create_task (async_function ())
150
166
151
- def clean_future () -> None :
152
- if not task .cancel ():
153
- try :
154
- clean = task .result ()
155
- except asyncio .CancelledError :
156
- pass
157
- else :
158
- if clean is not None :
159
- clean ()
167
+ @overload
168
+ def use_async_effect (
169
+ function : _AsyncEffectFunc ,
170
+ dependencies : Sequence [Any ] | ellipsis | None = ...,
171
+ ) -> None : ...
172
+
173
+
174
+ def use_async_effect (
175
+ function : _AsyncEffectFunc | None = None ,
176
+ dependencies : Sequence [Any ] | ellipsis | None = ...,
177
+ ) -> Callable [[_AsyncEffectFunc ], None ] | None :
178
+ """See the full :ref:`Use Effect` docs for details
179
+
180
+ Parameters:
181
+ function:
182
+ Applies the effect and can return a clean-up function
183
+ dependencies:
184
+ Dependencies for the effect. The effect will only trigger if the identity
185
+ of any value in the given sequence changes (i.e. their :func:`id` is
186
+ different). By default these are inferred based on local variables that are
187
+ referenced by the given function.
188
+
189
+ Returns:
190
+ If not function is provided, a decorator. Otherwise ``None``.
191
+ """
192
+ hook = current_hook ()
193
+ dependencies = _try_to_infer_closure_values (function , dependencies )
194
+ memoize = use_memo (dependencies = dependencies )
195
+ last_clean_callback : Ref [_EffectCleanFunc | None ] = use_ref (None )
196
+
197
+ def add_effect (function : _AsyncEffectFunc ) -> None :
198
+ def sync_executor () -> _EffectCleanFunc | None :
199
+ task = asyncio .create_task (function ())
160
200
161
- return clean_future
201
+ def clean_future () -> None :
202
+ if not task .cancel ():
203
+ try :
204
+ clean = task .result ()
205
+ except asyncio .CancelledError :
206
+ pass
207
+ else :
208
+ if clean is not None :
209
+ clean ()
210
+
211
+ return clean_future
162
212
163
213
async def effect (stop : asyncio .Event ) -> None :
164
214
if last_clean_callback .current is not None :
165
215
last_clean_callback .current ()
166
216
last_clean_callback .current = None
167
- clean = last_clean_callback .current = sync_function ()
217
+ clean = last_clean_callback .current = sync_executor ()
168
218
await stop .wait ()
169
219
if clean is not None :
170
220
clean ()
@@ -174,8 +224,8 @@ async def effect(stop: asyncio.Event) -> None:
174
224
if function is not None :
175
225
add_effect (function )
176
226
return None
177
- else :
178
- return add_effect
227
+
228
+ return add_effect
179
229
180
230
181
231
def use_debug_value (
0 commit comments