-2

When user type value on <input />, I want to switch focus.

But my issue is when I type value on refOne, codeOne is empty on checkFocus function, event I try to use setTimeout.

Strange thing is console.log('render codeOne', codeOne) has value, but codeOne inside the function is empty.

enter image description here

How to fix it ?

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

function ModalPhoneBox() => {
    const refOne = useRef<HTMLInputElement>(null);
    const refTwo = useRef<HTMLInputElement>(null);
    const refThree = useRef<HTMLInputElement>(null);

    const [codeData, setCodeData] = useState<FormInputType>({
      codeOne: '',
      codeTwo: '',
      codeThree: '',
    });

    const { codeOne, codeTwo, codeThre } = codeData;

    const checkFocus = () => {
        console.log('checkFocus');
        setTimeout(() => {
            if (
                refOne.current != null &&
                refTwo.current != null &&
                refThree.current != null &&
                refFour.current != null
            ) {
                console.log('0');
                console.log('codeOne', codeOne);
                if (codeOne && codeTwo === '') {
                    console.log('1');
                    refTwo.current.focus();
                }

                if (codeOne && codeTwo && codeThree === '') {
                    console.log('2');
                    refThree.current.focus();
                }
            }
        }, 1000);
    };

    console.log('render codeOne', codeOne);

    return (
                        <div className={styles.inputGroup}>
                        <div className={styles.inputBox}>
                            <input
                                ref={refOne}
                                maxLength={1}
                                onChange={(v: ChangeEvent<{ value: string }>) => {
                                    setCodeData({ ...codeData, codeOne: v.target.value });
                                    checkFocus();
                                }}
                                type="text"
                                placeholder={''}
                            />
                        </div>
                        <div className={styles.inputBox}>
                            <input
                                ref={refTwo}
                                maxLength={1}
                                onChange={(v: ChangeEvent<{ value: string }>) => {
                                    setCodeData({ ...codeData, codeTwo: v.target.value });
                                    checkFocus();
                                }}
                                type="text"
                                placeholder={''}
                            />
                        </div>
                        <div className={styles.inputBox}>
                            <input
                                ref={refThree}
                                maxLength={1}
                                onChange={(v: ChangeEvent<{ value: string }>) =>
                                    setCodeData({ ...codeData, codeThree: v.target.value })
                                }
                                type="text"
                                placeholder={''}
                            />
                        </div>
                    </div>
    );

export default ModalPhoneBox;
Morton
  • 5,380
  • 18
  • 63
  • 118
  • 2
    The code shown is jumping through more hoops than usual for the proposed duplicate, but the issue still appears to be the same. Immediately after calling `setCodeData` you call `checkFocus`, so when `checkFocus` is invoked the state has not been updated. Internally it has a timeout, but that doesn't change anything. The state at the time the function was invoked has not been updated. So the value for `codeOne` within that function will still have the old value. If you're looking to respond to state changes, you're probably looking for `useEffect`. – David Aug 03 '23 at 12:48
  • Thanks, you explain very clearly for me. – Morton Aug 04 '23 at 06:51

1 Answers1

1

To fix this issue, you can use the useEffect hook to trigger the focus switch after the state has been updated.

useEffect(() => {
    checkFocus();
}, [codeOne, codeTwo, codeThree]);

Using useEffect with the dependencies [codeOne, codeTwo, codeThree], This will ensure checkFocus function will be called after the state has been updated with the new values, and you should be able to switch the focus correctly.

murtuza hussain
  • 458
  • 1
  • 7
  • 18