[React] 커스텀 훅 만들기

728x90

[React] 커스텀 훅 만들기


 

로그인 화면을 구성할 때, 아이디 비밀번호 입력창을 구현하기 위해서는 State와 Onchange 함수가 필수적으로 사용됩니다.

const [id, setId] = useState('');
const onChangeId = useCallback((e) => {
setId(e.target.value);
}, []);

const [password, setPassword] = useState('');
const onChangePassword = useCallback((e) => {
setPassword(e.target.value);
}, []);

만약에 해당 페이지에 입력 폼이 훨씬 더 많아진다면 정말 귀찮은 일이 될 것입니다.

 

한 번에 두 가지 기능을 담당하도록 커스텀 훅을 만들어주고, 필요한 값을 반환하는 형태로 구현하면 코드를 훨씬 줄일 수 있습니다.

 

import { ChangeEvent, useCallback, useState } from 'react';

type InputEventHandler = (e: ChangeEvent<HTMLInputElement>) => void;

const useInput = (initialValue: string): [string, InputEventHandler] => {
  const [value, setValue] = useState(initialValue);
  const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
  }, []);
  return [value, onChange];
};

useInput이라는 커스텀 훅을 만들었습니다. 그 안에 setState와 onChage 메서드를 구현한 후, [a, b] 형태로 반환합니다.

 

useInput를 사용하는 컴포넌트에서는 다음과 같이 코드를 작성할 수 있습니다.

const [id, onChangeId] = useInput('');
const [pw, onChangePw] = useInput('');

초기값으로 ''이 선언되었으며, setState와 onChage메서드가 적용된 커스텀 훅이 완성되었습니다.

이렇게 반환된 값 [A, B]를 그대로 const로 정의하여 사용하는 것을 구조 분해 할당이라고 합니다.

 

이를 활용한 전체 코드는 다음과 같습니다.

import { ChangeEvent, useCallback, useState } from 'react';

type InputEventHandler = (e: ChangeEvent<HTMLInputElement>) => void;

const useInput = (initialValue: string): [string, InputEventHandler] => {
  const [value, setValue] = useState(initialValue);
  const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setValue(e.target.value);
  }, []);
  return [value, onChange];
};

export const LoginForm = () => {
  const [id, onChangeId] = useInput('');
  const [pw, onChangePw] = useInput('');

  return (
    <>
      <label>
        ID:
        <input type="text" value={id} onChange={onChangeId} />
      </label>
      <br />
      <label>
        PW:
        <input type="password" value={pw} onChange={onChangePw} />
      </label>
    </>
  );
};
export default LoginForm;
728x90