@@ -88,9 +88,10 @@ class LifeCycleHook:
8888 "__weakref__" ,
8989 "_context_providers" ,
9090 "_current_state_index" ,
91- "_effect_generators " ,
91+ "_pending_effects " ,
9292 "_render_access" ,
9393 "_rendered_atleast_once" ,
94+ "_running_effects" ,
9495 "_schedule_render_callback" ,
9596 "_schedule_render_later" ,
9697 "_state" ,
@@ -109,7 +110,8 @@ def __init__(
109110 self ._rendered_atleast_once = False
110111 self ._current_state_index = 0
111112 self ._state : tuple [Any , ...] = ()
112- self ._effect_generators : list [AsyncGenerator [None , None ]] = []
113+ self ._pending_effects : list [AsyncGenerator [None , None ]] = []
114+ self ._running_effects : list [AsyncGenerator [None , None ]] = []
113115 self ._render_access = Semaphore (1 ) # ensure only one render at a time
114116
115117 def schedule_render (self ) -> None :
@@ -131,7 +133,7 @@ def use_state(self, function: Callable[[], T]) -> T:
131133
132134 def add_effect (self , effect_func : Callable [[], AsyncGenerator [None , None ]]) -> None :
133135 """Add an effect to this hook"""
134- self ._effect_generators .append (effect_func ())
136+ self ._pending_effects .append (effect_func ())
135137
136138 def set_context_provider (self , provider : ContextProviderType [Any ]) -> None :
137139 self ._context_providers [provider .type ] = provider
@@ -150,29 +152,32 @@ async def affect_component_will_render(self, component: ComponentType) -> None:
150152 async def affect_component_did_render (self ) -> None :
151153 """The component completed a render"""
152154 self .unset_current ()
153- del self .component
154155 self ._rendered_atleast_once = True
155156 self ._current_state_index = 0
156157 self ._render_access .release ()
157158
158159 async def affect_layout_did_render (self ) -> None :
159160 """The layout completed a render"""
160161 try :
161- await gather (* [g .asend (None ) for g in self ._effect_generators ])
162+ await gather (* [g .asend (None ) for g in self ._pending_effects ])
163+ self ._running_effects .extend (self ._pending_effects )
162164 except Exception :
163- logger .exception ("Error during effect execution" )
165+ logger .exception ("Error during effect startup" )
166+ finally :
167+ self ._pending_effects .clear ()
164168 if self ._schedule_render_later :
165169 self ._schedule_render ()
166170 self ._schedule_render_later = False
171+ del self .component
167172
168173 async def affect_component_will_unmount (self ) -> None :
169174 """The component is about to be removed from the layout"""
170175 try :
171- await gather (* [g .aclose () for g in self ._effect_generators ])
176+ await gather (* [g .aclose () for g in self ._running_effects ])
172177 except Exception :
173- logger .exception ("Error during effect cancellation " )
178+ logger .exception ("Error during effect cleanup " )
174179 finally :
175- self ._effect_generators .clear ()
180+ self ._running_effects .clear ()
176181
177182 def set_current (self ) -> None :
178183 """Set this hook as the active hook in this thread
@@ -192,7 +197,7 @@ def unset_current(self) -> None:
192197 raise RuntimeError ("Hook stack is in an invalid state" ) # nocov
193198
194199 def _is_rendering (self ) -> bool :
195- return self ._render_access .value ! = 0
200+ return self ._render_access .value = = 0
196201
197202 def _schedule_render (self ) -> None :
198203 try :
0 commit comments