본문 바로가기
카테고리 없음

리액트 커스텀 훅(custom Hook) 모음 4가지

by 지삶앎 2022. 12. 5.
반응형

리액트의 훅을 커스텀해서 몇 가지 만들어보게 됐다.

useInput

import { ChangeEvent, ChangeEventHandler, useCallback, useState } from "react";

type InputValidator = (value: string) => string;

const useInput = (validator: InputValidator?, defaultValue?: string): [string, ChangeEventHandler, string] => {
  const [value, setValue] = useState<string>(defaultValue || "");
  const [error, setError] = useState<string>("");

  const onChange = useCallback(
    (e: ChangeEvent<HTMLInputElement>) => {
      setValue(e.target.value);

      const error = validator(e.target.value);
      if (error) {
        setError(error);
        return;
      }
      setError("");
    },
    [validator]
  );

  return [value, onChange, error];
};

export default useInput;

useInput은 인풋에서 텍스트를 입력할 때 주로 사용하는 useState와 validator를 결합한 커스텀 훅이다. 그래서 return은 value와 onChange 그리고 error를 return해준다. 배열로 사용한 이유는 useState가 배열로 리턴이 되다보니 따라하게 됐다. 순서에 상관없이 이용하고 싶다면 객체로 리턴을 해줘도 될 듯 싶다.

 

useInput은 validator와 defaultValue를 인자로 받고 있다. validator와 defaultValue는 null을 허용할 때도 있을 것 같아 ?를 추가해주었다. defaultValue가 있으면 useState의 초기값이 defaultValue가 되지만 없으면 빈 문자열로 초기값을 설정한다. 그 이후에 validator 로 검증하여 setError로 error를 담아주거나 빈 문자열을 담아준다.

 

그래서 사용하는 페이지의 코드를 보면 아래와 같다.

export default function SignIn() {
  const [userId, onChangeUserId, userIdError] = useInput(idValidator, "이메일");
  
  return (
        <LoginInputBox>
          <input
            type="email"
            id="email"
            name="email"
            placeholder="아이디"
            value={userId}
            className="text_input"
            onChange={onChangeUserId}
          />
          <p className="error_message">{userIdError}</p>
        </LoginInputBox>
	)

아이디와 관련하여 useInput을 사용했으며, 다양한 validator를 모아둔 validatorInput 파일에 idValidator를 임포트해서 사용한다. useInput을 사용했을 때 좋은 점은 매번 onChange 함수를 선언해주지 않아도 된다. 매번 validator와 setState(e.target.value)를 작성하여 코드가 길어지는데 hooks에서 처리해주니 코드 한 줄로 짧아진다. validator도 하나의 파일에 모아두니 관리하기가 편했다.

 

아래 validator 예시로 휴대폰 번호 검증하여 에러 메시지를 반환해주는 식이다.

export const phoneValidator = (phone: string) => {
  const rPhone = /01[016789]-[^0][0-9]{2,3}-[0-9]{3,4}/;
  if (phone.length !== 11) return "전화번호를 정확히 입력해주세요.";
  if (rPhone.test(phone)) return "전화번호를 정확히 입력해주세요.";
  return "";
};

 

useFocus

간단하게 만든 커스텀훅으로 페이지에서 input이 있을 때 시작하자마자 포커스를 해주는 hook이다.

import { useEffect, useRef } from "react";

export const useFocus = () => {
  const element = useRef<HTMLInputElement>(null);

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

  return element;
};

 

useConfirm

게시글을 삭제할 때 확인메시지를 띄우고 확인 시 함수를 실행하게 만드는 hook이다. 

export const useConfirm = (msg: string, onConfirm: () => void) => {
  const confirmAction = () => {
    if (confirm(msg)) {
      onConfirm();
    }
  };
  return confirmAction;
};

 

usePreventLeave

게시글을 작성하다가 실수로 나갈 수 있으니 그에 대한 방지하는 hooks이다. 자주 보던 이벤트인데 사용을 한 번도 안했던 것 같다. 이번 기회로 잘 사용하지 않을까 싶다. beforeunload는 window event로 창, 문서 및 해당 리소스가 언로드되려고 할 때 시작하는 이벤트이다. 

export const usePreventLeave = () => {
  const listener = (e: BeforeUnloadEvent) => {
    e.preventDefault;
    e.returnValue = "";
  };
  const enablePrevent = () => window.addEventListener("beforeunload", listener);
  const disablePrevent = () => window.removeEventListener("beforeunload", listener);
  return { enablePrevent, disablePrevent };
};
반응형

댓글