Replies: 1 comment 2 replies
-
cc @cipolleschi tagged you directly as I remember you are very familar with the textInput component and you helped us a lot previously with the |
Beta Was this translation helpful? Give feedback.
2 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Problem
This discussion tries to find a solution for this issue, that highlights how clearing a text input can be broken in react native:
The
TextInput
component uses an event count mechanism to keep the UI and JS state in sync. If JS is sending outdated state updates (such as a prop update afteronChangeText
) the event is dropped. Code references:We encountered a use case where this is problematic:
When clearing text: The user calls
textInputRef.clear()
in JS expecting it to get cleared. But the user might continues typing, and once the event from JS to set the TextInputs content to""
the event is dropped.Question: Is that a problem that you’d be open to fix in react-native core?
Solutions
There are multiple solutions that come to my mind. I opened this as a discussion so feel free to add your own, or comment on mine. I am trying to find the solution that works best and would be merged into react-native.
1. Adding an explicit
clear
view command that bypasses the event countRight now, when the user calls
ref.clear()
internally it will callsetTextAndSelection(viewTag, "", 0, 0)
which is subject to the event count mechanism.We could create a separate view command for clearing that’s not suing the event count from JS, but just takes the native one and increments it.
I have an example implementation here:
https://github.com/margelo/expensify-app-fork/blob/fix/composer-not-clearing-force-clear-event/patches/react-native+0.73.4+018+textInputClear.patch
It’s important that the event count is incremented natively, so any other events that might happened in between get dropped (e.g. JS sending the value prop).
2. Adding a way to force call
setTextAndSelection
or adding a new public view command sich asforceSetTextAndSelection
The idea is similar to the one above, we could either add a new public view command called
forceSetTextAndSelection
or add aforce: boolean
parameter tosetTextAndSelection
and expose it to the user.As explained in solution (1) we’d bypass and increment the event count on the native side.
This solution would also help in serving use case (2).
3. Using partial updates from native in JS
originally explained here
In react native the text input sends the whole text that's currently in the text input in the
onChange
/onChangeText
event callbacks. However, we maintain the "source of truth" for our text input in JavaScript in our react state variablevalue
which we pass as a prop to the<TextInput value={value} />
.So it can happen that we set our JS value to
""
to clear the input, but the native side is ignoring that event (as the JS thread is lagging behind in events), and sends us instead a new update with the current native input, which would be "aaaaaabbbbbb" by then.Instead of fully setting the whole native text we receive, we can only apply the updates that happened to the text to our JS
value
.Meaning if the input was "aaaaaa" and the user types "b", instead of taking the native text update and setting "aaaaaab" as our
value
, we just take the change"b"
and append it to our value:value
is "aaaaaa"value
to""
"b"
and appends it to ourvalue
, resulting in"" + "b"
="b"
value
prop, showing "b"So the user would see "aaaaaa" -> "aaaaaab" -> "b".
I have a PR for that here, as we need to receive the replacement range from the native side in JS to implement this:
4. Keeping it all on one thread
One solution would be to work with the text input only on the JS or UI thread. I don’t think thats a a real solution, as we want to keep the JS and UI thread independent from each other / none-blocking each other.
5. Force re-render TextInput
It could be fixed from the user side, without any changes to react-native, by force re-rendering the TextInput on clear. I think this is best explained in code:
However, i am not sure if such a user workaround is a good idea? I know that fabric recycles native views, but i still feel that this would be a bit overkill?
Any other ideas? Personally, I am leaning towards solution (1).
Beta Was this translation helpful? Give feedback.
All reactions