You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中调用.focus()提示not a function错误,求解决及优化方案

Fixing "focus() is not a function" Error & Improving OTP Input Focus Switching

Hey there! Let's break down why your OTP input focus switching isn't working and how to fix it, plus some better practices for this common use case.

The Root Cause of the Error

You're using React.createRef() to reference your custom OtpField components, but by default, React doesn't pass refs through to the underlying DOM element (like the <input> inside OtpField). That means fieldOne.current is actually the instance of the OtpField component, not the input node—so calling .focus() on it throws the "is not a function" error.

Step 1: Forward Refs to the Input in OtpField

First, you need to update your OtpField component to forward the ref it receives to the internal input element using React.forwardRef:

// Inside OtpField.js or wherever your component is defined
const OtpField = React.forwardRef((props, ref) => {
  // Pass the ref directly to your input element
  return <input ref={ref} {...props} />;
});

export default OtpField;

This makes sure that when you attach a ref to OtpField in your parent component, it points straight to the actual input DOM node, so .focus() will work as expected.

Step 2: Simplify Focus Switching Logic

Your current approach of manually linking each field's onChange to the next ref works, but it's repetitive. Let's clean this up with an array of refs and a reusable handler:

import React, { useRef } from 'react';
// ... your other imports

const SignUpVerification = () => {
  // Create an array of refs for all OTP fields
  const otpRefs = useRef([
    React.createRef(),
    React.createRef(),
    React.createRef(),
    React.createRef()
  ]);

  // Reusable handler to switch focus between fields
  const handleFocusSwitch = (index, e) => {
    // Limit each field to 1 character
    if (e.target.value.length > 1) return;

    // Move to next field if current has a value
    if (e.target.value && index < otpRefs.current.length - 1) {
      otpRefs.current[index + 1].current.focus();
    }
    // Move to previous field if current is cleared
    if (!e.target.value && index > 0) {
      otpRefs.current[index - 1].current.focus();
    }
  };

  return (
    <div style={{ display: 'flex' }}>
      <FormDiv style={{ textAlign: 'center' }}>
        <Nunito32 
          style={{ 
            display: 'inline-block', 
            textAlign: 'center', 
            marginRight: 236, 
            marginLeft: 200 
          }}
        >
          Verify your mobile number by entering the code we sent you
        </Nunito32>
        {/* Add display: flex to make flexDirection: row work */}
        <div style={{ flexDirection: 'row', display: 'flex' }}>
          {otpRefs.current.map((ref, index) => (
            <OtpField 
              key={index}
              ref={ref} 
              style={{ marginRight: 10.5 }} 
              onChange={(e) => handleFocusSwitch(index, e)}
              maxLength={1} // Enforce single character input
            />
          ))}
        </div>
        <PinkButton style={{ marginTop: 75 }}>Continue</PinkButton>
        <Nunito20>Send again</Nunito20>
      </FormDiv>
      <ImageContainer>
        <ImageDiv bg={signup} src={signup} alt="logo" />
      </ImageContainer>
    </div>
  );
};

export default SignUpVerification;

This adds a few nice improvements:

  • Automatic focus switching: Moves to the next field when a character is entered, and back to the previous when deleted
  • Input validation: Limits each field to exactly one character with maxLength and a check in the handler
  • Cleaner code: No more repetitive onChange handlers for each field

Bonus: Manage OTP State

If you want to collect the OTP value for submission, add a state variable to track each field's value:

import React, { useRef, useState } from 'react';

// ...

const SignUpVerification = () => {
  const [otpValue, setOtpValue] = useState(new Array(4).fill(''));
  const otpRefs = useRef([/* ... refs ... */]);

  const handleFocusSwitch = (index, e) => {
    const newOtp = [...otpValue];
    newOtp[index] = e.target.value.slice(0, 1);
    setOtpValue(newOtp);

    // ... existing focus logic ...
  };

  // Later, when submitting:
  const handleSubmit = () => {
    const fullOtp = otpValue.join('');
    console.log('Submitting OTP:', fullOtp);
    // Call your API with fullOtp here
  };

  // Update OtpField to use the state value:
  <OtpField 
    key={index}
    ref={ref} 
    style={{ marginRight: 10.5 }} 
    onChange={(e) => handleFocusSwitch(index, e)}
    maxLength={1}
    value={otpValue[index]}
  />
};

This makes it easy to access the full OTP string when the user clicks "Continue".

内容的提问来源于stack exchange,提问作者SImon Haddad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:56:02