리액트의 훅을 커스텀해서 몇 가지 만들어보게 됐다.
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 };
};
댓글