Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Client-side component events break input focus #1195

Open
Archmonger opened this issue Feb 11, 2024 Discussed in #1187 · 4 comments
Open

Client-side component events break input focus #1195

Archmonger opened this issue Feb 11, 2024 Discussed in #1187 · 4 comments
Labels
priority-1-high Should be resolved ASAP. type-bug About something that isn't working

Comments

@Archmonger
Copy link
Contributor

Discussed in #1187

Originally posted by williamneto January 13, 2024
So, while developing reactpy-material i faced a problem that might be related to the reactpy architecture for custom components.

To showcase the problem i created this small component, just a normal textfield. The problem is when attaching a on_change event to this custom component, the event on the page doesn't behavior as expected. Each time you type in the field (and trigger the onChange event) the page focus is moved out of the input element.

So, a simple custom TextField like that

import React from "react";
import ReactDOM from "react-dom";
import htm from "htm";

const html = htm.bind(React.createElement);

export function bind(node, config) {
  return {
    create: (type, props, children) => React.createElement(type, props, ...children),
    render: (element) => ReactDOM.render(element, node),
    unmount: () => ReactDOM.unmountComponentAtNode(node),
  }
}

export function TextField(attrs) {
  return html`
    <div>
      <input type="text" ...${attrs}>
    </div>`;
}
from pathlib import Path
from typing import Any
from reactpy.web.module import export, module_from_file
from reactpy import component

_js_module = module_from_file(
    "reactpy-events-problem",
    file=Path(__file__).parents[0] / "bundle.js"
)

new_text_field = export(_js_module, "TextField")

@component
def text_field(attrs: Any ={}):
    return new_text_field(attrs)

And when you try to use it like that

from reactpy import component, run, html, use_state
from reactpy_events_problem import text_field

@component
def app():
    text, set_text = use_state("Text")

    return html.div(
        html.h1(text),
        text_field(
            attrs={
                "value": text,
                "onChange": lambda e: set_text(e["target"]["value"])
            }
        )
    )

run(app)

You end up with this weird behavior at the page focus, making type in this field very unpratical

@Archmonger Archmonger added type-bug About something that isn't working priority-1-high Should be resolved ASAP. labels Feb 11, 2024
@Archmonger Archmonger changed the title Client side component event handlers break input focus Client-side component events break input focus Feb 11, 2024
@rmorshea
Copy link
Collaborator

Relevant code is here. What's probably happening is that the element is getting recreated.

With that said, despite the fact that render() on the custom component is always called, subsequent calls to ReactDOM.render on the same element should trigger an update rather than a render from scratch.

One possible cause is that the element React is mounting to is changing for some reason.

@rmorshea
Copy link
Collaborator

On a separate note, we might want to add a method to custom components (perhaps mount()) that's called exactly once when the custom component is first rendered to a given DOM element. This would match up with the new createRoot(...).render() workflow in ReactJS 18.

@shawncrawley
Copy link

I have confirmed this same exact behavior using a custom FormControl component from react-boostrap. I have also noticed what is likely the same root issue in a less annoying case using a custom Map component from pigeon-maps. In this latter case, the map flickers every time a change is triggered as if the image tiles are being re-rendered every time. This issue is a big deal based on what I hope to accomplish with reactpy and reactpy-django. So much so that I'd love to be part of the solution. I'm going to take a stab at detangling this, but this still all feels very black-boxy to me. Let me know if anyone else has made progress here before I waste too much time. Thanks!

@Archmonger
Copy link
Contributor Author

I don't believe anyone has had time to untangle this issue yet, so feel free to take a stab at it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
priority-1-high Should be resolved ASAP. type-bug About something that isn't working
Projects
None yet
Development

No branches or pull requests

3 participants