Home > Mobile >  Why is useRef focus not working in React?
Why is useRef focus not working in React?

Time:01-01

In React, I want that if something is typed into a form, another form is immediately set to focus.

For example:

<html>
  <head>
    <title>React App</title>
    <script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/[email protected]/babel.min.js"></script>
  </head>
 
  <body>
    <div id="mydiv"></div>
    <script type="text/babel"> 
                                                   //Now its basically like React
      function Inputs() {
        const [otp, setOtp] = React.useState([]); //Here are stored the Values of the numbers
        const itemsRef = React.useRef([]);       //Here are stored the refs of the numbers
        const setOtpfunction = (e, i) => {
          const key = parseInt(e.key);     //I first parse the key that i got from onKeyPress to a number 
          if (key) {
            let OTP = [...otp];
            OTP[i] = key;
            setOtp(OTP);                  //Then i update the numbers
            if (i < 5) {
              const nextForm = i   1;     //Here i say that the next item schould be the item with the index   1
              ref[i].focus();            //And here i set the focus. ref.current.focus() wouldnt work in this case
            }
          }
        };
        return (
          <div className="space-x-2">
            <input
              placeholder="first input"
              type="number"
              className="otpNumber"
              onChange={(e) => (e = null)} //that there is no error because there is no onChange function
              required
              onKeyPress={(e) => setOtpfunction(e, 0)}
              ref={(ref) => (itemsRef[0] = ref)}
              autoFocus
              value={otp[0] || ""}
            />
            <input
            placeholder="second input"
              type="number"
              className="otpNumber"
              onChange={(e) => (e = null)} //that there is no error because there is no onChange function
              onKeyPress={(e) => setOtpfunction(e, 1)}
              ref={(ref) => (itemsRef[1] = ref)}
              value={otp[1] || ""}
            />
            <input
              placeholder="third input"
              type="number"
              className="otpNumber"
              onChange={(e) => (e = null)} //that there is no error because there is no onChange function
              onKeyPress={(e) => setOtpfunction(e, 2)}
              ref={(ref) => (itemsRef[2] = ref)}
              value={otp[2] || ""}
            />
            <p>Now you can type in 1 number in the inputs and they are stored in UseState. But i want that if in the first input, one number is entered, it focuses the second input and so on</p>
          </div>
        );
      }
      class Render extends React.Component {
        render() {
          return (
            <div>
              <Inputs />
            </div>
          );
        }
      }
      ReactDOM.render(<Render />, document.getElementById("mydiv"));
    </script>
  </body>
</html>

The console's error was only a warning that you should compile your scripts for production. That's why I hid it.

I also tested it with document.getElemntbyId, which also didn´t work.

I hope you can understand what I mean. Thanks for any answers that can be provided!

CodePudding user response:

I would rather make a single Input component, that notifies the parent when the user types something and updates the state accordingly:

const OTP_LENGTH = 4;

export default function OTPForm() {
  const [index, setIndex] = useState(0);

  function done() {
    if (index === OTP_LENGTH - 1) {
      console.log("All inputs filled");
      return;
    }
    setIndex(index   1);
  }

  return (
    <form>
      {Array.from({ length: OTP_LENGTH }, (_, i) => (
        <Input key={i} isCurrent={i === index} done={done} />
      ))}
    </form>
  );
}

function Input({ isCurrent, done }) {
  const ref = useRef(null);

  useEffect(() => {
    if (isCurrent && ref.current) {
      ref.current.focus();
    }
  }, [isCurrent]);

  function onInput(event) {
    if (event.target.value > 1) {
      event.preventDefault();
      return;
    }
    if (event.target.value === 1) {
      done();
    }
  }

  return <input ref={ref} onInput={onInput} type="number"/>;
}

Up to you to expose proper onError / onSubmit handlers from the parent component.

  • Related