简体   繁体   中英

Using react refs to focus on sibling element

I am trying to create a react form that uses refs. What I need is when the user inputs a value in one input field. it should automatically focus on the next sibling element ie second input element and so on until the end of the input fields are reached and the form's value should get automatically gets saved into the state.

I am quite new to using react refs. I tried developing a basic working but is stuck on error:

TypeError: Cannot read property 'nextSibling' of undefined
Todo._handleKeyPress
  22 |    
  23 |    e.preventDefault();
  24 | 
> 25 |    let next = this.refs[field.name].nextSibling;
     | ^  26 |    if (next && next.tagName === "INPUT") {
  27 |      this.refs[field.name].nextSibling.focus();
  28 |    }




import ReactDOM from "react-dom";
import React, { Component } from "react";
import "./style.css";

class Todo extends Component {
  constructor(props) {
    super(props); // create a ref to store the textInput DOM element

    this.state= {

    }


    this.textInput1 = React.createRef();
    this.textInput2 = React.createRef();
    this.textInput3 = React.createRef();
  }

  _handleKeyPress = (e, field) => {
    e.preventDefault();

    let next = this.refs[field.name].nextSibling;
    if (next && next.tagName === "INPUT") {
      this.refs[field.name].nextSibling.focus();
    }
  };


submitForm = () => {

}


  render() {
    return (
      <React.Fragment>
        <form onSubmit={this.submitForm}>
          <input
            type="number"
            name={this.textInput1}
            maxLength="1"
            ref={this.textInput1}
            onKeyPress={e => this._handleKeyPress(e, this.textInput1)}
          />
          <input
            type="number"
            name={this.textInput2}
            maxLength="1"
            ref={this.textInput3}
            onKeyPress={e => this._handleKeyPress(e, this.textInput2)}
          />
          <input
            type="number"
            name={this.textInput3}
            maxLength="1"
            ref={this.textInput3}
            onKeyPress={e => this._handleKeyPress(e, this.textInput3)}
          />

          <button>Submit</button>
        </form>
      </React.Fragment>
    );
  }
}

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

I have included the demo code in the link: https://stackblitz.com/edit/react-6gsfxd . ANy kind of help is appreciated.

The second argument field is already a reference to the input element, you don't need to call it with this.refs .

I have made few changes in _handleKeyPress method.

import ReactDOM from "react-dom";
import React, { Component } from "react";
import "./style.css";

class Todo extends Component {
  constructor(props) {
    super(props); // create a ref to store the textInput DOM element

    this.state= {

    }


    this.textInput1 = React.createRef();
    this.textInput2 = React.createRef();
    this.textInput3 = React.createRef();
  }

  _handleKeyPress = (e, field) => {

    let next = field.current.nextSibling;
    field.current.nextSibling.focus();
  };


submitForm = () => {

}


  render() {
    return (
      <React.Fragment>
        <form onSubmit={this.submitForm}>
          <input
            type="number"
            name={this.textInput1}
            maxLength="1"
            ref={this.textInput1}
            onKeyUp={e => this._handleKeyPress(e, this.textInput1)}
          />
          <input
            type="number"
            name={this.textInput2}
            maxLength="1"
            ref={this.textInput2}
            onKeyUp={e => this._handleKeyPress(e, this.textInput2)}
          />
          <input
            type="number"
            name={this.textInput3}
            maxLength="1"
            ref={this.textInput3}
            onKeyUp={e => this._handleKeyPress(e, this.textInput3)}
          />

          <button>Submit</button>
        </form>
      </React.Fragment>
    );
  }
}

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

Example:

https://stackblitz.com/edit/react-fegfq3?file=index.js

const InputForm = () => {
  const focusChangeHandler = (e) => {
  const { value, name } = e.target;
  const [fieldName, fieldIndex] = name.split("-");
  if (parseInt(fieldIndex) < 4) {
    const nextfield = document.querySelector(
      `input[name=field-${parseInt(fieldIndex) + 1}]`
    );
    // If found, focus the next field
    if (nextfield !== null) {
      nextfield.focus();
    }
  }
};

return (
  <form>
    <input
      name="field-1"
      onChange={focusChangeHandler}
      type="text"
      maxLength="1"
    />
    <input
      name="field-2"
      onChange={focusChangeHandler}
      type="text"
      maxLength="1"
    />
    <input
      name="field-3"
      onChange={focusChangeHandler}
      type="text"
      maxLength="1"
    />
    <input
      name="field-4"
      onChange={focusChangeHandler}
      type="text"
      maxLength="1"
    />
  </form>
);

};

export default InputForm;

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