React version: 16.13.1
<input> tag controlled, by setting its value in response to onChangeLink to code example:
https://gist.github.com/iain-merrick-fanduel/b9cea57baa9f20a5d288a0fcd6e7ee5e
Adapted from CodePen example (https://codepen.io/gaearon/pen/VmmPgp?editors=0010) on https://reactjs.org/docs/forms.html
If the transformation changes the value, the cursor is moved to the end of the input.
Cursor should remain at the original position if possible (this is the behaviour of the TextInput component in React Native).
This is very similar to https://github.com/facebook/react/issues/14904, but doesn't look quite the same:
In case this is browser-specific, I'm using Chrome 80 on OS X 10.14.6.
As far as I know, this is the intended usage, as the docs specifically give this example:
handleChange(event) {
this.setState({value: event.target.value.toUpperCase()});
}
That example exhibits the same bug — you can't edit the text field in the middle.
This has nothing to do with React, that's normal browser behaviour
In hand-written HTML, you'd normally fix this by saving the cursor position before changing the text, and restoring it afterwards. But React doesn't provide that low-level access (by design).
Maybe React could manage the cursor position automatically? This would bring parity with React Native, where the TextInput component behaves as expected.
But React doesn't provide that low-level access (by design).
Well, that's where you are wrong. It's not that hard to implement this in React. Here is a demo: https://codesandbox.io/s/boring-dirac-utq82
Oho, neat! I can probably use this, thanks!
Is this something that could/should be added as default behavior for the <input> component? I can't think of scenarios where you would _not_ want this, and even if you want something different (maybe slightly more refined for your specific input transformation) you could override it anyway. The example in the documentation would benefit from this.
Alternatively, the example code could be updated, but it seems like a lot of boilerplate for a simple task.
It's actually a little strange that the example docs use this approach. I've read that since React uses event pooling one needs to capture the event and pass the captured event to the setState function.
If you modify your handleChange function to the following, it should work as expected.
handleChange(event) {
let value = event.target.value.replace('/ /g','_');
this.setState({value});
}
Event pooling allows reuse of the event and because the setState is asynchronous, there is no guarantee on when it will be called and what value it holds at that instance.
Is this something that could/should be added as default behavior for the component?
I think it is a bit against React philosophy. React is about making DOM transformations declarative, not about changing how it works. If you need such behaviour, you can make your own <Input/> component which does just that (or more).
The example in the documentation would benefit from this.
I agree, there probably should be a warning in the docs explaining that it's not as _ straightforward_ to modify input this way.
If you modify your handleChange function to the following, it should work as expected.
No, your modified code is strictly equivalent to original code. What you can't do is use the event object asynchronously, including setState(() => ...) form, without calling e.persist().
As far as I know, this is the intended usage, as the docs specifically give this example
Woah. This advice in docs seems pretty bad. I don't think this is supported in that sense.
This behavior is expected (React can't know where to put the selection after you've modified it).
I'll remove the misleading docs section.
Most helpful comment
Well, that's where you are wrong. It's not that hard to implement this in React. Here is a demo: https://codesandbox.io/s/boring-dirac-utq82