@@ -52,6 +52,95 @@ Why Avoid Mutation?
52
52
Unfortunately, IDOM does not understand that when a value is mutated, it may have
53
53
changed. As a result, mutating values will not trigger re-renders. Thus, you must be
54
54
careful 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:
56
57
57
58
.. 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