-
Notifications
You must be signed in to change notification settings - Fork 47.1k
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
controlled input cursor jumps to end (again) #14904
Comments
This is quite weird. Same code works for me on CodeSandbox: https://codesandbox.io/s/vqn79m09r3 Not sure what's going on here. |
Seems UMD-specific. |
Thank you very much for reporting this. It's a serious regression in the last patch release, and exposed some lacking coverage in our test suite regarding UMD bundles. I have a fix ready in #14914. |
Great! thank you for the fix. |
This is fixed in 16.8.3. Unfortunately unpkg doesn't seem to pick up the 16.8.3 version yet from its default redirect. |
That's OK, I replaced the resources with the specific release artifacts to test and it works great now. 👍 |
@gaearon it flipped for me and I'm actually having the same problem OP reported in your CodeSandbox, but not in his codepen. Should that be? Chrome 74 |
I've updated from react 16.8.1 to 16.8.6. Still having the same problem... |
I am running into this same issue. I have created the following fiddle which is a boiled down version of what I have. https://jsfiddle.net/CodeMedic42/87f9gnow/ Ultimately once the event stack finishes it appears that React clears the value in the input since it is controlled. Then when the timeout fires it sets the correct value but at this time the position is lost. I tried the fix this by handling the state internally to the TestInput Component as in the following fiddle. https://jsfiddle.net/CodeMedic42/bt3w05m7/ But after debugging it appears that setState causes getDerivedStateFromProps to be called which has the old value and I end up in the same mess. I feel I need getDerivedStateFromProps because I have handle the case where the value can change externally and I need to set the state to this new value. I believe if getDerivedStateFromProps was NOT called for a setState change then perhaps this problem would not exist, at least for my second example. But I am not familiar with the internals of React to even feel confident in this suggestion, so please take it with a grain of salt of course. |
Okay based on my second fiddle I have come up with the following solution which should not require weird cursor manipulation. Please review, test, and use at your discretion. I have tested it a little and it appears to work. If I run into any problems I will post here. |
Is this issue fixed? I'm having the same problem in 16.8.6. |
Here is how I reproduce this issue. Is there something I'm doing wrong (or should do differently)? const InputChild = props => {
const [value, setValue] = useState("");
useEffect(() => {
if (props.value === value) return;
setValue(props.value);
}, [props.value, value]);
return (
<input
placeholder="Enter text"
type="text"
value={value}
onChange={e => {
props.onChange(e.target.value);
}}
/>
);
};
const Input = () => {
const [value, setValue] = useState("");
return <InputChild value={value} onChange={setValue} />;
}; |
There are 2 possible ways to get around this issue, as far as I can tell. Solution 1: Use the <input
type="text"
value={props.value}
onChange={e => {
props.onChange(e.target.value);
}}
/> Solution 2: Update the local state simultaneously as the parent state. <input
type="text"
value={props.value}
onChange={e => {
setState(e.target.value)
props.onChange(e.target.value);
}}
/> |
You're round-tripping the value change from @gaearon suggested in #955 (comment) to call What I've done to workaround is to make the |
In your example if you make a change, the InputChild component will be rendered once with outdated values. This is because the new value isn't set until useEffect. So whatever you typed will be erased for one frame, then put back after useEffect. This is enough to make the cursor position ambiguous to the browser. As a hack suggestion, you can swap useEffect with useMemo. This works because useMemo runs before render. |
Do you want to request a feature or report a bug?
Bug
What is the current behavior?
when typing in a controlled input, the cursor always jumps to the end. This was an old issue that seems to have resurfaced.
this code pen used in the docs here has the problem in all browsers as far as I have been able to test.
What is the expected behavior?
because we are using the state to update the component as soon as it's changed, the input element should be able to keep the cursor in the same place.
Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
I'm at latest (16.8.2) and I tested on Chrome, FireFox, and Edge on Windows
as far as I know, this was working at some point, though I don't know how long ago. possibly even before "Fiber"
The text was updated successfully, but these errors were encountered: