@@ -449,7 +449,8 @@ <h1>Source code for edifice.hooks</h1><div class="highlight"><pre>
449449
450450< span class ="sd "> An **initializer function** is a function of no arguments.</ span >
451451
452- < span class ="sd "> If an **initializer function** is passed to :func:`use_state`, then the</ span >
452+ < span class ="sd "> If an **initializer function** is passed to :func:`use_state` instead</ span >
453+ < span class ="sd "> of an initial value, then the</ span >
453454< span class ="sd "> **initializer function** will be called once before</ span >
454455< span class ="sd "> this :func:`components`’s first render to get the **initial state**.</ span >
455456
@@ -512,11 +513,20 @@ <h1>Source code for edifice.hooks</h1><div class="highlight"><pre>
512513< span class ="sd "> Do not mutate the state variable. The old state variable must be left</ span >
513514< span class ="sd "> unmodified so that it can be compared to the new state variable during</ span >
514515< span class ="sd "> the next render.</ span >
515- < span class ="sd "> Instead create a shallow `copy <https://docs.python.org/3/library/copy.html#copy.copy>`_</ span >
516- < span class ="sd "> of the state, modify the copy, then call the **setter function** with the modified copy.</ span >
516+
517+ < span class ="sd "> If Python does not have an</ span >
518+ < span class ="sd "> `immutable <https://docs.python.org/3/glossary.html#term-immutable>`_</ span >
519+ < span class ="sd "> version of your state data structure,</ span >
520+ < span class ="sd "> like for example the :code:`dict`, then you just have to take care to never</ span >
521+ < span class ="sd "> mutate it.</ span >
522+
523+ < span class ="sd "> Instead of mutating a state :code:`list`, create a</ span >
524+ < span class ="sd "> shallow `copy <https://docs.python.org/3/library/copy.html#copy.copy>`_</ span >
525+ < span class ="sd "> of the :code:`list`, modify the copy, then call the **setter function**</ span >
526+ < span class ="sd "> with the modified copy.</ span >
517527
518528< span class ="sd "> .. code-block:: python</ span >
519- < span class ="sd "> :caption: Updater function with shallow copy</ span >
529+ < span class ="sd "> :caption: Updater function with shallow copy of a list </ span >
520530
521531< span class ="sd "> from copy import copy</ span >
522532< span class ="sd "> from typing import cast</ span >
@@ -537,12 +547,35 @@ <h1>Source code for edifice.hooks</h1><div class="highlight"><pre>
537547< span class ="sd "> for t in x:</ span >
538548< span class ="sd "> Label(text=t)</ span >
539549
540- < span class ="sd "> A good technique for declaring immutable state datastructures is to use</ span >
541- < span class ="sd "> `frozen dataclasses <https://docs.python.org/3/library/dataclasses.html#frozen-instances>`_.</ span >
542- < span class ="sd "> Use the</ span >
543- < span class ="sd "> `replace() <https://docs.python.org/3/library/dataclasses.html#dataclasses.replace>`_</ span >
544- < span class ="sd "> function to update the dataclass.</ span >
550+ < span class ="sd "> Techniques for `immutable <https://docs.python.org/3/glossary.html#term-immutable>`_ datastructures in Python</ span >
551+ < span class ="sd "> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</ span >
552+
553+ < span class ="sd "> - `Shallow copy <https://docs.python.org/3/library/copy.html#copy.copy>`_.</ span >
554+ < span class ="sd "> We never need a deep copy because all the data structure items are also immutable.</ span >
555+ < span class ="sd "> - `Frozen dataclasses <https://docs.python.org/3/library/dataclasses.html#frozen-instances>`_.</ span >
556+ < span class ="sd "> Use the</ span >
557+ < span class ="sd "> `replace() <https://docs.python.org/3/library/dataclasses.html#dataclasses.replace>`_</ span >
558+ < span class ="sd "> function to update the dataclass.</ span >
559+ < span class ="sd "> - Tuples (:code:`my_list:tuple[str, ...]`) instead of lists (:code:`my_list:list[str]`).</ span >
560+
561+ < span class ="sd "> .. code-block:: python</ span >
562+ < span class ="sd "> :caption: Updater function with shallow copy of a tuple</ span >
563+
564+ < span class ="sd "> from typing import cast</ span >
565+
566+ < span class ="sd "> def Stateful(self):</ span >
567+ < span class ="sd "> x, x_setter = use_state(cast(tuple[str, ...], ()))</ span >
568+
569+ < span class ="sd "> def updater(x_previous:tuple[str, ...]) -> tuple[str, ...]:</ span >
570+ < span class ="sd "> return x_previous + ("Label Text " + str(len(x_previous)),)</ span >
545571
572+ < span class ="sd "> with View():</ span >
573+ < span class ="sd "> Button(</ span >
574+ < span class ="sd "> title="Add One",</ span >
575+ < span class ="sd "> on_click = lambda _event: x_setter(updater)</ span >
576+ < span class ="sd "> )</ span >
577+ < span class ="sd "> for t in x:</ span >
578+ < span class ="sd "> Label(text=t)</ span >
546579< span class ="sd "> Args:</ span >
547580< span class ="sd "> initial_state: The initial **state value** or **initializer function**.</ span >
548581< span class ="sd "> Returns:</ span >
@@ -653,19 +686,26 @@ <h1>Source code for edifice.hooks</h1><div class="highlight"><pre>
653686< span class ="sd "> :caption: use_async to fetch from the network</ span >
654687
655688< span class ="sd "> @component</ span >
656- < span class ="sd "> def Asynchronous (self):</ span >
657- < span class ="sd "> myword, myword_set = use_state("")</ span >
689+ < span class ="sd "> def WordDefinition (self, word:str ):</ span >
690+ < span class ="sd "> definition, definition_set = use_state("")</ span >
658691
659692< span class ="sd "> async def fetcher():</ span >
660693< span class ="sd "> try:</ span >
661- < span class ="sd "> x = await fetch_word_from_the_internet()</ span >
662- < span class ="sd "> myword_set(x)</ span >
694+ < span class ="sd "> definition_set("Fetch definition pending")</ span >
695+ < span class ="sd "> x = await fetch_definition_from_the_internet(word)</ span >
696+ < span class ="sd "> definition_set(x)</ span >
663697< span class ="sd "> except asyncio.CancelledError:</ span >
664- < span class ="sd "> myword_set ("Fetch word cancelled")</ span >
698+ < span class ="sd "> definition_set ("Fetch definition cancelled")</ span >
665699< span class ="sd "> raise</ span >
700+ < span class ="sd "> except BaseException:</ span >
701+ < span class ="sd "> defintion_set("Fetch definition failed")</ span >
702+
703+ < span class ="sd "> cancel_fetcher = use_async(fetcher, word)</ span >
666704
667- < span class ="sd "> _cancel_fetcher = use_async(fetcher, 0)</ span >
668- < span class ="sd "> Label(text=myword)</ span >
705+ < span class ="sd "> with VBoxView():</ span >
706+ < span class ="sd "> Label(text=word)</ span >
707+ < span class ="sd "> Label(text=definition)</ span >
708+ < span class ="sd "> Button(text="Cancel fetch", on_click=lambda _:cancel_fetcher())</ span >
669709
670710< span class ="sd "> Cancellation</ span >
671711< span class ="sd "> ============</ span >
0 commit comments