简体   繁体   中英

React.js controlled text cursor focus issue

I have a simple controlled input of type number like below.

<input type="number" value={+value} step={1} onChange={this.updateMyChange} />

My value often returns a decimal number like 123.123 . My problem is, when I try edit the value. The cursor loses focus and shifts to the beginning ignoring the whole numbers as soon as the decimal places are cleared. Like below:

在此输入图像描述

How do I address this? Immediately after the decimal places are cleared, the cursor jumps to the beginning thereby making it impossible to edit the whole numbers. Any help would be appreciated.

Update Below is the remaining code as requested by the user below.

render() {
   const {value} = this.state;

   return (
      <input type="number" value={+value} step={1} onChange={this.updateMyChange} />
   )
}

And my updateMyChange method is simply

updateMyChange(e) {
  this.setState({ value: e.target.value });
}

It does nothing much simply sets the new value. The cursor position jumps to the end as soon as decimal places are cleared. It does not set cursor for whole numbers.

This is how React updates an input field's value:

node.setAttribute(attributeName, '' + value);

When you set value attribute using that method, the caret goes to the beginning of the field, regardless of using React. You can see what I am saying in this fiddle - https://jsfiddle.net/5v896g3q/ (Just try and position the cursor in the field, between changes).

According to MDN , setAttribute is unstable when dealing with value . The recommended way of changing value is by accessing the value property of the element, like element.value = newValue . If you use that approach, all seems to go as expected.

This is all I can tell for sure. Now let's speculate a little. When you type anything in that field, you are:

  1. updating the value of the input
  2. reading that value, and sending to React as state
  3. React updates the value of the input, with the new state

When you are typing on the field, step 3 is likely to have no impact, because when the value comes back, the input already got it right. Except on the case with the float number. When your field reads 1. , the actual value React updates the field with is 1 . And React uses the evil method ( setAttribute ).

So, a workaround I found was setting the value of the field, using the proper method, before React touches it, on componentWillUpdate :

componentWillUpdate(nProps, nState){
  this.refs.input.value = '0' + nState.value
}

The problem there, is that it is "numerizing" the value on every change, meaning I won't be able to have a point ( 1. ). For that reason, I will only edit the input in case new value is 2 characters shorter than the old one (point + digit after point):

componentWillUpdate(nProps, nState){
  if(this.state.value.length - nState.value.length === 2){
    this.refs.input.value = '0' + nState.value
  }
}

Working example - https://jsfiddle.net/bsoku268/3/

note: the fiddle is for demonstration purposes, and not supposed to be a bulletproof solution, as there are many ways of interacting with an input field, such as copy & paste, drag & drop, autofill, etc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM