React controlled input cursor jumps

*爱你&永不变心* 提交于 2019-12-22 06:46:39

问题


I am using React and have formatted a controlled input field, which works fine when I write some numbers and click outside the input field. However, when I want to edit the input, the cursor jumps to the front of the value in the input field. This only occur in IE, and not in e.g. Chrome. I've seen that for some programmers the cursor jumps to the back of the value. So I think the reason that my cursor is jumping to the front is because the value is aligned to the right instead of to the left in the input field. Here is a senario:

My first input is 1000 Then I want to edit it to 10003, but the result is 31000

Is there a way to controll that the cursor should not jump?


回答1:


Taking a guess by your question, your code most likely looks similar to this:

    <input
        autoFocus="autofocus"
        type="text"
        value={this.state.value}
        onChange={(e) => this.setState({value: e.target.value})}
    />

This may vary in behaviour if your event is handled with onBlur but essentially its the same issue. The behaviour here, which many have stated as a React "bug", is actually expected behaviour.

Your input control's value is not an initial value of the control when its loaded, but rather an underlying value bound to this.state. And when the state changes the control is re-rendered by React.

Essentially this means that the control is recreated by React and populated by the state's value. The problem is that it has no way of knowing what the cursor position was before it was recreated.

One way of solving this which I found to work is remembering the cursor position before it was re-rendered as follows:

    <input
        autoFocus="autofocus"
        type="text"
        value={this.state.value}
        onChange={(e) => {
            this.cursor = e.target.selectionStart;
            this.setState({value: e.target.value});
        }}
        onFocus={(e) => {
            e.target.selectionStart = this.cursor;
        }}
    />



回答2:


This is my solution:

import React, { Component } from "react";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: ""
    };

    //get reference for input
    this.nameRef = React.createRef();

    //Setup cursor position for input
    this.cursor;
  }

  componentDidUpdate() {
    this._setCursorPositions();
  }

  _setCursorPositions = () => {
    //reset the cursor position for input
    this.nameRef.current.selectionStart = this.cursor;
    this.nameRef.current.selectionEnd = this.cursor;
  };

  handleInputChange = (key, val) => {
    this.setState({
      [key]: val
    });
  };

  render() {
    return (
      <div className="content">
        <div className="form-group col-md-3">
          <label htmlFor="name">Name</label>
          <input
            ref={this.nameRef}
            type="text"
            autoComplete="off"
            className="form-control"
            id="name"
            value={this.state.name}
            onChange={event => {
              this.cursor = event.target.selectionStart;
              this.handleInputChange("name", event.currentTarget.value);
            }}
          />
        </div>
      </div>
    );
  }
}

export default App;




回答3:


My cursor jumped always to the end of the line. This solution seems to fix the problem (from github):

import * as React from "react";
import * as ReactDOM from "react-dom";

class App extends React.Component<{}, { text: string }> {
  private textarea: React.RefObject<HTMLTextAreaElement>;
  constructor(props) {
    super(props);
    this.state = { text: "" };
    this.textarea = React.createRef();
  }

  handleChange(e: React.ChangeEvent<HTMLTextAreaElement>) {
    const cursor = e.target.selectionStart;
    this.setState({ text: e.target.value }, () => {
      if (this.textarea.current != null)
        this.textarea.current.selectionEnd = cursor;
    });
  }

  render() {
    return (
      <textarea
        ref={this.textarea}
        value={this.state.text}
        onChange={this.handleChange.bind(this)}
      />
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));



回答4:


Here is my solution

const Input = () => {
    const [val, setVal] = useState('');
    const inputEl = useRef(null);

    const handleInputChange = e => {
      const { value, selectionEnd } = e.target;
      const rightCharsCount = value.length - selectionEnd;
      const formattedValue = parseInt(value.replace(/\D/g, ''), 10).toLocaleString();
      const newPosition = formattedValue.length - rightCharsCount;

      setVal(formattedValue);

      setTimeout(() => {
        inputEl.current.setSelectionRange(newPosition, newPosition);
      }, 0);
    };

    return <input ref={inputEl} value={val} onChange={handleInputChange} />;
};


来源:https://stackoverflow.com/questions/46000544/react-controlled-input-cursor-jumps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!