Rendering Component

import React, {useEffect, useRef, useState} from 'react'
import Container from '../Container'
import Title from '../form/Title'
import Submit from '../form/Submit'

const OTP_LENGTH = 6
export default function EmailVerification() {    
    const [otp,
        setOtp] = useState(new Array(OTP_LENGTH).fill(""))
    const[currentOtpIndex,setCurrentOtpIndex] = useState(0);    
    const inputRef = useRef();   

    useEffect(() => {
        inputRef.current?.focus();        
    },[currentOtpIndex])

    const handleOtpChange = ({target},ind) => {
      const newOtp = [...otp]   ;            
      const newValue = target.value;               
      newOtp[ind] = newValue.substring(newValue.length-1,newValue.length);                                    
      setCurrentOtpIndex(ind+1);        
      setOtp(newOtp);
    }
    return (
        <div
            className='fixed inset-0 bg-primary -z-10 flex justify-center items-center'>
            <Container>
                <form className='bg-secondary rounded p-6 space-y-6'>
                    <Title>Email Verification</Title>
                    <div className="flex space-x-6">
                        {otp.map((_, index) => {
                            return (<input
                                ref={(index === currentOtpIndex) ? inputRef:null}                                
                                key={index}
                                onChange={(e) => {handleOtpChange(e,index)}}
                                type="number"
                                className="w-12 h-12 outline-none rounded border-dark-subtle focus:border-white transition
                                                bg-transparent text-xl font-semibold border-2 text-center text-white"/>)
                        })}
                    </div>         
                   <Submit value="Verify"/>
                </form>
            </Container>
        </div>
    )
}

Dear All,
I am using this code to enter 6 digits of OTP for email verification. Here to prevent the user to be able to input multiple digits in any field, I am using a substring. This substring will get the last digit and update the current index of the field. When I am doing console.log, I am getting the correct values for OTP and newOtp, but on the screen, those changes are not reflected. That means, on screen, if I enter multiple digits in any field, i am not seeing the last digits but all the digits of that field.

Can you tell me what is wrong with my code ?

Hi @shoaibhita

Welcome to FCC.

Perhaps you need to use controlled component in the input field. Try setting the value attribute like in the example below. You can also set the min and max value of the input so that you only capture digits in the range 0-9.

 <input
  ...
  value={otp[index]}
  min={0}
  max={9}
/>

I hope that helps.

Thanks a lot, nibble, yes by making it controlled input it worked.

But if you can tell just for my information, why otp fields states are not directly reflected in the fields ?

1 Like

Because when the input filed changes, the handleOtpChange function is invoked with the event object and the corresponding index. You retrieve the value of the input field from the event object, access the last digit and update state. The component is re-rendered after state update but the value of the modified input field doesn’t know that state has changed because its value doesn’t depend on state(uncontrolled).

By setting the value attribute to opt[index], you have only one source of truth, state. When a user enters a digit in the input filed, the callback is invoked, you retrieve the digit and update state. The component re-renders after state update and the value of the input field is updated with the updated value in state.

1 Like

Thanks a lot, dear for a clear and detailed explanation. Yes, this is what I was looking fo r and it toughened my concept of React. I am glad, I found this forum.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.