Skip to content

Commit ad88514

Browse files
committed
misc additionar to mutability docs
also adds some JS to only load examples when they come into view
1 parent 806d9f6 commit ad88514

File tree

3 files changed

+117
-1
lines changed

3 files changed

+117
-1
lines changed

docs/source/_custom_js/src/index.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,16 @@ export function mountWidgetExample(
2525
});
2626

2727
const mountEl = document.getElementById(mountID);
28+
let isMounted = false;
29+
triggerIfInViewport(mountEl, () => {
30+
if (!isMounted) {
31+
activateView(mountEl, serverInfo, useActivateButton);
32+
isMounted = true;
33+
}
34+
});
35+
}
2836

37+
function activateView(mountEl, serverInfo, useActivateButton) {
2938
if (!useActivateButton) {
3039
mountWithLayoutServer(mountEl, serverInfo);
3140
return;
@@ -67,3 +76,19 @@ export function mountWidgetExample(
6776

6877
mountEl.appendChild(enableWidgetButton);
6978
}
79+
80+
function triggerIfInViewport(element, callback) {
81+
const observer = new window.IntersectionObserver(
82+
([entry]) => {
83+
if (entry.isIntersecting) {
84+
callback();
85+
}
86+
},
87+
{
88+
root: null,
89+
threshold: 0.1, // set offset 0.1 means trigger if atleast 10% of element in viewport
90+
}
91+
);
92+
93+
observer.observe(element);
94+
}

docs/source/adding-interactivity/dangers-of-mutability/_examples/moving_dot_broken.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# :linenos:
2+
13
from idom import component, html, run, use_state
24

35

docs/source/adding-interactivity/dangers-of-mutability/index.rst

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,95 @@ Why Avoid Mutation?
5252
Unfortunately, IDOM does not understand that when a value is mutated, it may have
5353
changed. As a result, mutating values will not trigger re-renders. Thus, you must be
5454
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:
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

Comments
 (0)