Skip to content

Commit 6a18487

Browse files
committed
complete minimum doc update
1 parent 00f8048 commit 6a18487

9 files changed

Lines changed: 100 additions & 34 deletions

File tree

docs/source/core-concepts.rst

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,32 @@ accepted a list of strings and turned it into a series of paragraph elements:
2626

2727
.. code-block::
2828
29-
def Paragraphs(list_of_text):
29+
def paragraphs(list_of_text):
3030
return idom.html.div([idom.html.p(text) for text in list_of_text])
3131
3232
3333
Stateful Elements
3434
-----------------
3535

36-
...
36+
A Stateful Element is one which uses a :ref:`Life Cycle Hook`. These lifecycle hooks
37+
allow you to add state to otherwise stateless functions. To create a stateful element
38+
you'll need to apply the :func:`~idom.core.element.element` decorator to a coroutine_
39+
whose body contains a hook usage. We'll demonstrate that with a simple
40+
:ref:`click counter`:
41+
42+
.. testcode::
43+
44+
import idom
45+
46+
47+
@idom.element
48+
async def ClickCount():
49+
count, set_count = idom.hooks.use_state(0)
50+
51+
return idom.html.button(
52+
{"onClick": lambda event: set_count(count + 1)},
53+
[f"Click count: {count}"],
54+
)
3755

3856

3957
Element Layout
@@ -45,22 +63,54 @@ elements (turning them into VDOM) and scheduling their re-renders when they
4563
:meth:`~idom.core.layout.Layout.update`. To create a layout, you'll need an
4664
:class:`~idom.core.element.Element` instance, which will become its root, and won't
4765
ever be removed from the model. Then you'll just need to call and await a
48-
:meth:`~idom.core.layout.Layout.render` which will return a bundle containing VDOM:
66+
:meth:`~idom.core.layout.Layout.render` which will return a :ref:`JSON Patch`:
4967

5068
.. testcode::
5169

52-
...
70+
async with idom.Layout(ClickCount()) as layout:
71+
patch = await layout.render()
5372

5473
The layout also handles the triggering event handlers. Normally this is done
55-
automatically by a :ref:`Renderer <Layout Renderer>`, but for now we'll do this
56-
manually by digging into the :class:`~idom.core.layout.LayoutUpdate` object to find
57-
the ID of ``click_count``'s event handler so we can execute it. Once we have the ID, we
58-
can pass it, and a fake event, to the layout's :meth:`~idom.core.layout.Layout.trigger`
59-
method. Then we just have to re-render the layout and see what changed:
74+
automatically by a :ref:`Renderer <Layout Renderer>`, but for now we'll to it manually.
75+
To do use we can use a trick to hard-code the ``event_handler_id`` so we can pass it,
76+
and a fake event, to the layout's :meth:`~idom.core.layout.Layout.trigger` method. Then
77+
we just have to re-render the layout and see what changed:
6078

6179
.. testcode::
6280

63-
...
81+
from idom.core.layout import LayoutEvent
82+
83+
84+
event_handler_id = "on-click"
85+
86+
87+
@idom.element
88+
async def ClickCount():
89+
count, set_count = idom.hooks.use_state(0)
90+
91+
@idom.event(target_id=event_handler_id) # <-- trick to hard code event handler ID
92+
def on_click(event):
93+
set_count(count + 1)
94+
95+
return idom.html.button(
96+
{"onClick": on_click},
97+
[f"Click count: {count}"],
98+
)
99+
100+
101+
async with idom.Layout(ClickCount()) as layout:
102+
patch_1 = await layout.render()
103+
104+
fake_event = LayoutEvent(event_handler_id, [{}])
105+
await layout.trigger(fake_event)
106+
patch_2 = await layout.render()
107+
108+
for change in patch_2.changes:
109+
if change["path"] == "/children/0":
110+
count_did_increment = change["value"] == "Click count: 1"
111+
112+
assert count_did_increment
113+
64114

65115
Layout Renderer
66116
---------------
@@ -80,19 +130,19 @@ callback that's called by the renderer to events it should execute.
80130
from idom.core import SingleStateRenderer, EventHandler
81131
from idom.core.layout import LayoutEvent
82132

83-
sent_updates = []
133+
134+
sent_patches = []
84135

85136

86-
async def send(update):
87-
sent_updates.append(update)
88-
if len(sent_updates) == 5:
137+
async def send(patch):
138+
sent_patches.append(patch)
139+
if len(sent_patches) == 5:
89140
# if we didn't cancel the renderer would continue forever
90141
raise asyncio.CancelledError()
91142

92143

93144
async def recv():
94-
fake_event_data = [{}]
95-
event = LayoutEvent(event_handler_id, fake_event_data)
145+
event = LayoutEvent(event_handler_id, [{}])
96146

97147
# We need this so we don't flood the render loop with events.
98148
# In practice this is never an issue since events won't arrive
@@ -102,11 +152,11 @@ callback that's called by the renderer to events it should execute.
102152
return event
103153

104154

105-
async with SingleStateRenderer(idom.Layout(ClickCount(0))) as renderer:
155+
async with SingleStateRenderer(idom.Layout(ClickCount())) as renderer:
106156
context = None # see note below
107157
await renderer.run(send, recv, context)
108158

109-
assert len(sent_updates) == 5
159+
assert len(sent_patches) == 5
110160

111161

112162
.. note::
@@ -140,9 +190,9 @@ starting to add support for asyncio like
140190
In the case of our :class:`~idom.server.sanic.SanicRenderServer` types we have one
141191
implementation per builtin :ref:`Renderer <Layout Renderer>`:
142192

143-
- :class:`idom.server.sanic.PerClientState`
193+
- :class:`idom.server.sanic.PerClientStateServer`
144194

145-
- :class:`idom.server.sanic.SharedClientState`
195+
- :class:`idom.server.sanic.SharedClientStateServer`
146196

147197
The main thing to understand about server implementations is that they can function in
148198
two ways - as a standalone application or as an extension to an existing application.
@@ -157,13 +207,13 @@ the model:
157207
.. code-block:: python
158208
159209
import idom
160-
from idom.server.sanic import PerClientState
210+
from idom.server.sanic import PerClientStateServer
161211
162212
@idom.element
163213
def View(self):
164214
return idom.html.h1(["Hello World"])
165215
166-
app = PerClientState(View)
216+
app = PerClientStateServer(View)
167217
app.run("localhost", 5000)
168218
169219
@@ -184,11 +234,12 @@ The implementation registers hooks into the application to server the model once
184234
def View(self):
185235
return idom.html.h1(["Hello World"])
186236
187-
per_client_state = PerClientState(View)
237+
per_client_state = PerClientStateServer(View)
188238
per_client_state.register(app)
189239
190240
app.run("localhost", 5000)
191241
192242
193243
.. _pure functions: https://en.wikipedia.org/wiki/Pure_function
194244
.. _side effects: https://en.wikipedia.org/wiki/Side_effect_(computer_science)
245+
.. _coroutine: https://docs.python.org/3/glossary.html#term-coroutine

docs/source/examples.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ Try clicking the image 🖱️
7676
.. interactive-widget:: slideshow
7777

7878

79+
Click Counter
80+
-------------
81+
82+
.. literalinclude:: examples/click_count.py
83+
84+
.. interactive-widget:: click_count
85+
86+
7987
To Do List
8088
----------
8189

docs/source/examples/click_count.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33

44
@idom.element
5-
async def ClickCount(self):
6-
count, set_count = idom.hook.use_state(0)
5+
async def ClickCount():
6+
count, set_count = idom.hooks.use_state(0)
77

8-
async def increment(event):
9-
set_count(count + 1)
10-
11-
return idom.html.button({"onClick": increment}, [f"Click count: {count}"])
8+
return idom.html.button(
9+
{"onClick": lambda event: set_count(count + 1)},
10+
[f"Click count: {count}"],
11+
)
1212

1313

1414
display(ClickCount)

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ Libraries for defining and controlling interactive webpages with Python
1212

1313
installation
1414
getting-started
15+
core-concepts
1516
life-cycle-hooks
1617
javascript-modules
17-
core-concepts
1818
how-it-works
1919
specifications
2020
extra-features

docs/source/known-issues.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ Known Issues
44
.. [GH166] https://github.com/rmorshea/idom/issues/166
55
.. [GH195] https://github.com/rmorshea/idom/issues/195
66
.. [GH202] https://github.com/idom-team/idom/issues/202
7+
.. [GH203] https://github.com/idom-team/idom/issues/203

docs/source/life-cycle-hooks.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ cases the :ref:`**Basic Hooks**` should be enough, however the remaining
88

99
.. note::
1010

11-
At the moment not all of React's built-in hooks have been implemented. In the
12-
future they will be added as the need arises.
11+
Not all of React's built-in hooks have been implemented. In the future they will be
12+
added, but if you have a particular need for a missing hook post an issue [GH203]_.
1313

1414
.. contents::
1515
:local:
@@ -290,3 +290,4 @@ Under construction...
290290
.. _side effects: https://en.wikipedia.org/wiki/Side_effect_(computer_science)
291291
.. _memoization: https://en.wikipedia.org/wiki/Memoization
292292
.. _premature optimization: https://en.wikiquote.org/wiki/Donald_Knuth#Computer_Programming_as_an_Art_(1974)
293+
.. _gh issues: https://github.com/idom-team/idom/issues

docs/source/specifications.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,4 +162,9 @@ To clearly describe the VDOM schema we've created a `JSON Schema <https://json-s
162162
JSON Patch
163163
----------
164164

165-
Under construction...
165+
Updates to VDOM modules are sent using the `JSON Patch`_ specification.
166+
167+
... this section is still under construction :)
168+
169+
170+
.. _JSON Patch:: http://jsonpatch.com/

idom/core/layout.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ async def _create_layout_update(self, element: AbstractElement) -> LayoutUpdate:
147147
old_model = element_state.model.copy() # we copy because it will be mutated
148148
new_model = await self._render_element(element_state)
149149
changes = make_patch(old_model, new_model).patch
150-
return element_state.path, changes
150+
return LayoutUpdate(path=element_state.path, changes=changes)
151151

152152
async def _render_element(self, element_state: ElementState) -> Dict[str, Any]:
153153
try:

0 commit comments

Comments
 (0)