Input에 Focus 주기 with react hook form

이수빈·2024년 7월 31일
0

React

목록 보기
20/21
  • js를 이용해서 만약 input에 특정길이만큼 입력했을때 자동으로 다음 input으로 focus가 가도록 하는 코드는 다음과 같다.
document.addEventListener('DOMContentLoaded', () => {
  const input1 = document.getElementById('input1');
  const input2 = document.getElementById('input2');

  input1.addEventListener('input', () => {
    if (input1.value.length === input1.maxLength) {
      input2.focus();
    }
  });
});
  • 간단하다. 컴포넌트를 재사용할 때는, hook form의 useController를 사용해서 prop들을 넘겨준다.

  • react hook form에서는 setFocus라는 메소드를 제공하기 때문에 직접 돔에 접근해서 focus를 주지 않아도 쉽게 다음 focus로 이동하도록 구현 할 수 있다.

import React from 'react';
import { useForm, useController } from 'react-hook-form';
import { TextField, Button, Box } from '@mui/material';

const InputField = ({ name, control, maxLength, setFocus, nextField }) => {
  const { field } = useController({ name, control });

  const handleChange = (event) => {
    field.onChange(event);
    if (event.target.value.length >= maxLength && nextField) {
      setFocus(nextField);
    }
  };

  return (
    <TextField
      {...field}
      variant="outlined"
      inputProps={{ maxLength }}
      onChange={handleChange}
    />
  );
};

function App() {
  const { control, handleSubmit, setFocus } = useForm();
  const onSubmit = (data) => console.log(data);

  return (
    <Box component="form" onSubmit={handleSubmit(onSubmit)} noValidate autoComplete="off">
      <InputField
        name="input1"
        control={control}
        maxLength={5}
        setFocus={setFocus}
        nextField="input2"
      />
      <InputField
        name="input2"
        control={control}
        maxLength={5}
        setFocus={setFocus}
        nextField={null} // 마지막 입력창이므로 null
      />
      <Button type="submit" variant="contained" color="primary">
        Submit
      </Button>
    </Box>
  );
}

export default App;
  • 이때, controller prop을 커스텀에서 사용할때, field의 ref값이 존재한다.

  • 결국 focus가 되는 이동하는 원리는 ref를 통해 직접 돔에 접근해서 focus를 바꾸는 것이기 때문에, ref값을 hook form이 제어하도록 전달해줘야한다.

  • material UI같은 경우 ref와 inputRef라는 속성을 분리해서 사용한다.

ref) https://mui.com/material-ui/api/input-base/#input-base-prop-inputProps

  • 공식문서에 가보면 InputProps에 다음과 같은 말이 나온다.

The ref is forwarded to the root element.

  • inputRef는 material UI안에 있는 input태그에 ref를 전달하는 prop이다. 그래서 ref로 전달하는 방식이 아닌, inputRef라는 prop을 통해 전달해야 한다.

  • 만약 컴포넌트에 ref를 prop으로 전달하고 싶다면 ? react의 forwardRef와 useImperativeHandle를 사용해 처리해야한다.

import React, { forwardRef, useImperativeHandle, useRef } from 'react';

const ChildComponent = forwardRef((props, ref) => {
  const inputRef = useRef();

  useImperativeHandle(ref, () => ({
    focusInput: () => {
      inputRef.current.focus();
    }
  }));

  return <input ref={inputRef} type="text" />;
});

export default ChildComponent;
import React, { useRef } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const childRef = useRef();

  const handleFocus = () => {
    if (childRef.current) {
      childRef.current.focusInput();
    }
  };

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={handleFocus}>Focus on Input</button>
    </div>
  );
}

export default ParentComponent;
profile
응애 나 애기 개발자

0개의 댓글