1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
import htm from 'htm';
import { h } from 'preact';
import { useState, useCallback } from 'preact/hooks';
const html = htm.bind(h);
// configuration used to show behavior vs. workaround
let childFirst = true;
const Config = () => html`
<label>
<input
type="checkbox"
checked=${childFirst}
onchange=${evt => {
childFirst = evt.target.checked;
}}
/>
Set child state before parent state.
</label>
`;
const Child = ({ items, setItems }) => {
let [pendingId, setPendingId] = useState(null);
if (!pendingId) {
setPendingId(
(pendingId = Math.random()
.toFixed(20)
.slice(2))
);
}
const onInput = useCallback(
evt => {
let val = evt.target.value,
_items = [...items, { _id: pendingId, val }];
if (childFirst) {
setPendingId(null);
setItems(_items);
} else {
setItems(_items);
setPendingId(null);
}
},
[childFirst, setPendingId, setItems, items, pendingId]
);
return html`
<div class="item-editor">
${items.map(
(item, idx) => html`
<input
key=${item._id}
value=${item.val}
oninput=${evt => {
let val = evt.target.value,
_items = [...items];
_items.splice(idx, 1, { ...item, val });
setItems(_items);
}}
/>
`
)}
<input
key=${pendingId}
placeholder="type to add an item"
oninput=${onInput}
/>
</div>
`;
};
const Parent = () => {
let [items, setItems] = useState([]);
return html`
<div><${Config} /><${Child} items=${items} setItems=${setItems} /></div>
`;
};
export default Parent;
|