Skip to content

Commit 1ac1c7a

Browse files
committed
add element and component identity
At the moment, whenever a particular branch of a layout is updated, all the state (i.e. hooks and event handlers) that live within that branch are thrown away and reconstructed. Given IDOM’s current implementation for Layout this is unavoidable. To resolve this issue, we need to add a concept of “keys” which can be used to indicate the identity of an element within the layout structure. For example, if you have a list of elements that get re-ordered when a button is pressed, their state should be preserved, and reassigned to their new location in the layout. By default React requires keys to be used to communicate element identity whenever the order or number of simbling elements can change. While there are clear performance benefits for adhering to this stipulation, it’s often confusing for new developers. React has the further advantage of the JSX syntax, which makes it easier for the program to determine exactly when keys must be supplied by the user. To make the experience for new users simpler, and due to a lack of inforcement via JSX, IDOM will be to assume that any element without a key is new. Thus, for IDOM, keys will primarilly be a tool for optimization rather than a functional requirement.
1 parent 897a30c commit 1ac1c7a

File tree

10 files changed

+363
-231
lines changed

10 files changed

+363
-231
lines changed

docs/source/core-concepts.rst

+4-6
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,10 @@ which we can re-render and see what changed:
8585
[f"Click count: {count}"],
8686
)
8787

88-
async with idom.Layout(ClickCount(key="test-component")) as layout:
88+
async with idom.Layout(ClickCount()) as layout:
8989
patch_1 = await layout.render()
9090

91-
fake_event = LayoutEvent(target="/test-component/onClick", data=[{}])
91+
fake_event = LayoutEvent(target="/onClick", data=[{}])
9292
await layout.dispatch(fake_event)
9393
patch_2 = await layout.render()
9494

@@ -135,7 +135,7 @@ callback that's called by the dispatcher to events it should execute.
135135

136136

137137
async def recv():
138-
event = LayoutEvent(target="/test-component/onClick", data=[{}])
138+
event = LayoutEvent(target="/onClick", data=[{}])
139139

140140
# We need this so we don't flood the render loop with events.
141141
# In practice this is never an issue since events won't arrive
@@ -145,9 +145,7 @@ callback that's called by the dispatcher to events it should execute.
145145
return event
146146

147147

148-
async with SingleViewDispatcher(
149-
idom.Layout(ClickCount(key="test-component"))
150-
) as dispatcher:
148+
async with SingleViewDispatcher(idom.Layout(ClickCount())) as dispatcher:
151149
context = None # see note below
152150
await dispatcher.run(send, recv, context)
153151

requirements/check-style.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
black
22
flake8
3+
flake8-print
34
pep8-naming
45
flake8-idom-hooks >=0.4.0
56
isort >=5.7.0

src/idom/core/component.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ def component(function: ComponentRenderFunction) -> Callable[..., "Component"]:
2121
"""
2222

2323
@wraps(function)
24-
def constructor(*args: Any, key: str = "", **kwargs: Any) -> Component:
25-
return Component(function, key, args, kwargs)
24+
def constructor(*args: Any, **kwargs: Any) -> Component:
25+
return Component(function, args, kwargs)
2626

2727
return constructor
2828

@@ -48,11 +48,10 @@ class Component(AbstractComponent):
4848
def __init__(
4949
self,
5050
function: ComponentRenderFunction,
51-
key: str,
5251
args: Tuple[Any, ...],
5352
kwargs: Dict[str, Any],
5453
) -> None:
55-
self.key = key
54+
self.key = kwargs.get("key", "")
5655
self._function = function
5756
self._args = args
5857
self._kwargs = kwargs

src/idom/core/hooks.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from __future__ import annotations
2+
13
import asyncio
24
from logging import getLogger
35
from threading import get_ident as get_thread_id
@@ -20,6 +22,7 @@
2022

2123
from typing_extensions import Protocol
2224

25+
import idom
2326
from idom.utils import Ref
2427

2528
from .component import AbstractComponent
@@ -384,10 +387,10 @@ class LifeCycleHook:
384387
def __init__(
385388
self,
386389
component: AbstractComponent,
387-
schedule_render: Callable[[AbstractComponent], None],
390+
layout: idom.core.layout.Layout,
388391
) -> None:
389392
self.component = component
390-
self._schedule_render_callback = schedule_render
393+
self._schedule_render_callback = layout.update
391394
self._schedule_render_later = False
392395
self._is_rendering = False
393396
self._rendered_atleast_once = False

0 commit comments

Comments
 (0)