3030
3131
3232__all__ = [
33- "use_state " ,
33+ "use_callback " ,
3434 "use_effect" ,
35+ "use_memo" ,
3536 "use_reducer" ,
36- "use_callback" ,
3737 "use_ref" ,
38- "use_memo " ,
38+ "use_state " ,
3939]
4040
4141logger = getLogger (__name__ )
@@ -110,15 +110,15 @@ def use_effect(
110110
111111@overload
112112def use_effect (
113- function : _EffectApplyFunc ,
113+ function : _SyncEffectFunc ,
114114 dependencies : Sequence [Any ] | ellipsis | None = ...,
115115) -> None : ...
116116
117117
118118def use_effect (
119- function : _EffectApplyFunc | None = None ,
119+ function : _SyncEffectFunc | None = None ,
120120 dependencies : Sequence [Any ] | ellipsis | None = ...,
121- ) -> Callable [[_EffectApplyFunc ], None ] | None :
121+ ) -> Callable [[_SyncEffectFunc ], None ] | None :
122122 """See the full :ref:`Use Effect` docs for details
123123
124124 Parameters:
@@ -134,37 +134,87 @@ def use_effect(
134134 If not function is provided, a decorator. Otherwise ``None``.
135135 """
136136 hook = current_hook ()
137-
138137 dependencies = _try_to_infer_closure_values (function , dependencies )
139138 memoize = use_memo (dependencies = dependencies )
140139 last_clean_callback : Ref [_EffectCleanFunc | None ] = use_ref (None )
141140
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 ]: ...
147165
148- def sync_function () -> _EffectCleanFunc | None :
149- task = asyncio .create_task (async_function ())
150166
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 ())
160200
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
162212
163213 async def effect (stop : asyncio .Event ) -> None :
164214 if last_clean_callback .current is not None :
165215 last_clean_callback .current ()
166216 last_clean_callback .current = None
167- clean = last_clean_callback .current = sync_function ()
217+ clean = last_clean_callback .current = sync_executor ()
168218 await stop .wait ()
169219 if clean is not None :
170220 clean ()
@@ -174,8 +224,8 @@ async def effect(stop: asyncio.Event) -> None:
174224 if function is not None :
175225 add_effect (function )
176226 return None
177- else :
178- return add_effect
227+
228+ return add_effect
179229
180230
181231def use_debug_value (
0 commit comments