@@ -130,16 +130,6 @@ def _create_layout_update(self, component: AbstractComponent) -> LayoutUpdate:
130130 self ._render_component (old_state , new_state , component )
131131 changes = make_patch (getattr (old_state , "model" , {}), new_state .model ).patch
132132
133- # replace model and state in parent
134- if hasattr (new_state , "parent_ref" ):
135- parent = new_state .parent_ref ()
136- if parent is not None :
137- parent .children_by_key [new_state .key ] = new_state
138- parent .model ["children" ][new_state .index ] = new_state .model
139-
140- # replace in global state
141- self ._model_state_by_component_id [id (component )] = new_state
142-
143133 # hook effects must run after the update is complete
144134 for state in new_state .iter_children ():
145135 if hasattr (state , "life_cycle_hook" ):
@@ -166,6 +156,26 @@ def _render_component(
166156 logger .exception (f"Failed to render { component } " )
167157 new_state .model = {"tagName" : "__error__" , "children" : [str (error )]}
168158
159+ if old_state is not None and old_state .component is not component :
160+ del self ._model_state_by_component_id [id (old_state .component )]
161+ self ._model_state_by_component_id [id (component )] = new_state
162+
163+ try :
164+ parent = new_state .parent
165+ except AttributeError :
166+ pass
167+ else :
168+ key , index = new_state .key , new_state .index
169+ if old_state is not None :
170+ assert (key , index ) == (old_state .key , old_state .index ,), (
171+ "state mismatch during component update - "
172+ f"key { key !r} !={ old_state .key } "
173+ f"or index { index } !={ old_state .index } "
174+ )
175+ parent .children_by_key [key ] = new_state
176+ # need to do insertion in case where old_state is None and we're appending
177+ parent .model ["children" ][index : index + 1 ] = [new_state .model ]
178+
169179 def _render_model (
170180 self ,
171181 old_state : Optional [_ModelState ],
@@ -259,8 +269,8 @@ def _render_model_children(
259269 else :
260270 child = str (child )
261271 child_type = STRING_TYPE
262- # The key doesn't matter since we won't look it up - all that matter is
263- # that the key is unique ( which this approach guarantees)
272+ # The specific key doesn't matter here since we won't look it up - all
273+ # we care about is that the key is unique, which object() can guarantee.
264274 key = object ()
265275 raw_typed_children_by_key [key ] = (child_type , child )
266276
@@ -288,16 +298,11 @@ def _render_model_children(
288298 elif child_type is COMPONENT_TYPE :
289299 old_child_state = old_state .children_by_key .get (key )
290300 if old_child_state is not None :
291- old_component = old_child_state .life_cycle_hook .component
292- del self ._model_state_by_component_id [id (old_component )]
293301 new_child_state = old_child_state .new (new_state , child )
294302 else :
295303 hook = LifeCycleHook (child , self )
296304 new_child_state = _ModelState (new_state , index , key , hook )
297305 self ._render_component (old_child_state , new_child_state , child )
298- new_children .append (new_child_state .model )
299- new_state .children_by_key [key ] = new_child_state
300- self ._model_state_by_component_id [id (child )] = new_child_state
301306 else :
302307 new_children .append (child )
303308
@@ -317,9 +322,6 @@ def _render_model_children_without_old_state(
317322 life_cycle_hook = LifeCycleHook (child , self )
318323 child_state = _ModelState (new_state , index , key , life_cycle_hook )
319324 self ._render_component (None , child_state , child )
320- new_children .append (child_state .model )
321- new_state .children_by_key [key ] = child_state
322- self ._model_state_by_component_id [id (child )] = child_state
323325 else :
324326 new_children .append (str (child ))
325327
@@ -344,6 +346,7 @@ class _ModelState:
344346 "key" ,
345347 "_parent_ref" ,
346348 "life_cycle_hook" ,
349+ "component" ,
347350 "patch_path" ,
348351 "key_path" ,
349352 "model" ,
@@ -373,6 +376,7 @@ def __init__(
373376
374377 if life_cycle_hook is not None :
375378 self .life_cycle_hook = life_cycle_hook
379+ self .component = life_cycle_hook .component
376380
377381 self .event_targets : Set [str ] = set ()
378382 self .children_by_key : Dict [str , _ModelState ] = {}
0 commit comments