@@ -52,6 +52,95 @@ Why Avoid Mutation?
5252Unfortunately, IDOM does not understand that when a value is mutated, it may have
5353changed. As a result, mutating values will not trigger re-renders. Thus, you must be
5454careful to avoid mutation whenever you want IDOM to re-render a component. For example,
55- in the code below
55+ the intention of the code below is to make the red dot move when you touch or hover over
56+ the preview area. However it doesn't - the dot remains stationary:
5657
5758.. idom :: _examples/moving_dot_broken
59+
60+ The problem is with this section of code:
61+
62+ .. literalinclude :: _examples/moving_dot_broken.py
63+ :language: python
64+ :lines: 13-14
65+ :linenos:
66+ :lineno-start: 13
67+
68+ This code mutates the ``position `` dictionary from the prior render instead of using the
69+ state variable's associated state setter. Without calling setter IDOM has no idea that
70+ the variable's data has been modified. While it can be possible to get away with
71+ mutating state variables, it's highly dicsouraged. Doing so can cause strange and
72+ unpredictable behavior. As a result, you should always treat the data within a state
73+ variable as immutable.
74+
75+ To actually trigger a render we need to call the state setter. To do that we'll assign
76+ it to ``set_position `` instead of the unused ``_ `` variable we have above. Then we can
77+ call it by passing a *new * dictionary with the values for the next render. Notice how,
78+ by making these alterations to the code, that the dot now follows your pointer when
79+ you touch or hover over the preview:
80+
81+ .. idom :: _examples/moving_dot
82+
83+
84+ .. dropdown :: Local mutation can be alright
85+ :color: info
86+ :animate: fade-in
87+
88+ While code like this causes problems:
89+
90+ .. code-block ::
91+
92+ position["x"] = event["clientX"] - outer_div_bounds["x"]
93+ position["y"] = event["clientY"] - outer_div_bounds["y"]
94+
95+ It's ok if you mutate a fresh dictionary that you have *just * created before calling
96+ the state setter:
97+
98+ .. code-block ::
99+
100+ new_position = {}
101+ new_position["x"] = event["clientX"] - outer_div_bounds["x"]
102+ new_position["y"] = event["clientY"] - outer_div_bounds["y"]
103+ set_position(new_position)
104+
105+ It's actually nearly equivalent to having written:
106+
107+ .. code-block ::
108+
109+ set_position(
110+ {
111+ "x": event["clientX"] - outer_div_bounds["x"],
112+ "y": event["clientY"] - outer_div_bounds["y"],
113+ }
114+ )
115+
116+ Mutation is only a problem when you change data assigned to existing state
117+ variables. Mutating an object you’ve just created is okay because no other code
118+ references it yet. Changing it isn’t going to accidentally impact something that
119+ depends on it. This is called a “local mutation.” You can even do local mutation
120+ while rendering. Very convenient and completely okay!
121+
122+ Python provides a number of mutable built in data types:
123+
124+ - :ref: `Dictionaries <working with dictionaries >`
125+ - :ref: `Lists <working with lists >`
126+ - :ref: `Sets <working with sets >`
127+
128+ Below we suggest a number of strategies for safely working with these types...
129+
130+
131+ Working with Dictionaries
132+ -------------------------
133+
134+ There are a number of different ways to idiomatically construct dictionaries
135+
136+
137+ Working with Lists
138+ ------------------
139+
140+
141+ Working with Sets
142+ -----------------
143+
144+
145+ Working with Nested Data
146+ ------------------------
0 commit comments