Skip to content

Commit adcccb9

Browse files
committed
actually fix #684
To do this we keep a buffer of changed values client-side. Then, as the server pushes renders to the client, we check whether the server-rendered value matches the what was put in the buffer. If it does, then we simply use the latest value in the buffer and ignore the rendered value. If the rendered value is different than the rendered value, then we clear the buffer.
1 parent c9536f6 commit adcccb9

File tree

4 files changed

+82
-3
lines changed

4 files changed

+82
-3
lines changed

docs/source/_custom_js/package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/client/packages/idom-client-react/src/components.js

+38
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export function Element({ model }) {
3838
}
3939
} else if (model.tagName == "script") {
4040
return html`<${ScriptElement} model=${model} />`;
41+
} else if (model.tagName == "input") {
42+
return html`<${InputElement} model=${model} />`;
4143
} else if (model.importSource) {
4244
return html`<${ImportedElement} model=${model} />`;
4345
} else {
@@ -68,6 +70,42 @@ function StandardElement({ model }) {
6870
);
6971
}
7072

73+
function InputElement({ model }) {
74+
const layoutContext = React.useContext(LayoutContext);
75+
const props = createElementAttributes(model, layoutContext.sendEvent);
76+
77+
const observedValues = React.useState([])[0];
78+
79+
if (observedValues) {
80+
if (observedValues[0] === props.value) {
81+
observedValues.shift();
82+
props.value = observedValues[observedValues.length - 1];
83+
} else {
84+
observedValues.length = 0;
85+
}
86+
}
87+
88+
const userOnChange = props.onChange;
89+
if (userOnChange && !model.eventHandlers.onChange.preventDefault) {
90+
props.onChange = (event) => {
91+
observedValues.push(event.target.value);
92+
userOnChange(event);
93+
};
94+
}
95+
96+
// Use createElement here to avoid warning about variable numbers of children not
97+
// having keys. Warning about this must now be the responsibility of the server
98+
// providing the models instead of the client rendering them.
99+
return React.createElement(
100+
model.tagName,
101+
props,
102+
...createElementChildren(
103+
model,
104+
(model) => html`<${Element} key=${model.key} model=${model} />`
105+
)
106+
);
107+
}
108+
71109
function ScriptElement({ model }) {
72110
const ref = React.useRef();
73111
React.useEffect(() => {

src/client/packages/idom-client-react/src/element-utils.js

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ function createEventHandler(eventName, sendEvent, eventSpec) {
3939
if (typeof value === "object" && value.nativeEvent) {
4040
if (eventSpec["preventDefault"]) {
4141
value.preventDefault();
42-
} else if (eventName === "onChange") {
43-
value.nativeEvent.target.value = value.target.value;
4442
}
4543
if (eventSpec["stopPropagation"]) {
4644
value.stopPropagation();

temp.py

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import asyncio
2+
3+
from idom import component, event, html, run, use_state
4+
5+
6+
@component
7+
def App():
8+
recipient, set_recipient = use_state("Alice")
9+
message, set_message = use_state("")
10+
11+
@event(prevent_default=True)
12+
async def handle_submit(event):
13+
set_message("")
14+
print("About to send message...")
15+
await asyncio.sleep(5)
16+
print(f"Sent '{message}' to {recipient}")
17+
18+
return html.form(
19+
{"onSubmit": handle_submit, "style": {"display": "inline-grid"}},
20+
html.label(
21+
"To: ",
22+
html.select(
23+
{
24+
"value": recipient,
25+
"onChange": lambda event: set_recipient(event["target"]["value"]),
26+
},
27+
html.option({"value": "Alice"}, "Alice"),
28+
html.option({"value": "Bob"}, "Bob"),
29+
),
30+
),
31+
html.input(
32+
{
33+
"type": "text",
34+
"placeholder": "Your message...",
35+
"value": message,
36+
"onChange": lambda event: set_message(event["target"]["value"]),
37+
}
38+
),
39+
html.button({"type": "submit"}, "Send"),
40+
)
41+
42+
43+
run(App)

0 commit comments

Comments
 (0)