summaryrefslogtreecommitdiff
path: root/preact/demo/stateOrderBug.js
blob: b9f333d705a142f443c18e1822fe65106d22527b (plain)
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;