Skip to content

Commit e5d4fc1

Browse files
committed
_render_component must update state pointers
1 parent 88124ef commit e5d4fc1

File tree

1 file changed

+24
-20
lines changed

1 file changed

+24
-20
lines changed

src/idom/core/layout.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)