본문 바로가기
React

😀 React Custom Hook

by frontChoi 2026. 6. 2.
반응형

 React Custom Hook 이란

React에서 Custom Hook(커스텀 훅) 은 여러 컴포넌트에서 반복되는 상태(state) 및 로직을 재사용하기 위해 만드는 함수 React의 기본 Hook(useState, useEffect 등)을 조합해서 직접 만드는 Hook이라고 생각하면 된다.

 

useCounter를 통해 CustomHook 배우기

// useCounter.ts
import { useState } from "react";

function useCounter(initialValue = 0) {
  const [counter, setCounter] = useState<number>(initialValue);

  const increase = () => setCounter((prev) => prev + 1);
  const decrease = () =>
    setCounter((prev) => {
      if (prev > 0) return prev - 1;
      return 0;
    });
  const reset = () => setCounter(initialValue);
  return {
    counter,
    increase,
    decrease,
    reset,
  };
}

export default useCounter;
// User.tsx
import useCounter from "../hooks/useCounter";
function Home() {
  const { counter, increase, decrease, reset } = useCounter(0);
  return (
    <div className="container">
      카운터 커스텀 훅<p>값:{counter}</p>
      <button onClick={increase}>더하기</button>
      <button onClick={decrease}>빼기</button>
      <button onClick={reset}>리셋</button>
    </div>
  );
}

export default Home;

 

useCounter를 둠으로써 이점

  • 상태 관리 로직을 재사용할 수 있다
  • 로직 재사용
  • 컴포넌트가 깔끔해짐
  • 관심사 분리

 

 

useCounter를 실무에서 사용할 일은 거의 없다.

그리하여 form validation을 만들었다

 

useForm.ts

Form Validation(폼 검증) 하는 커스텀 훅

 

확장성을 위해 제네릭으로 선언하여, 관리하였다

Errors또한 제네릭으로 관리하도록 하였다

import { useState } from "react";
type Errors<T> = {
  [K in keyof T]?: string;
};
// 확장성을 위해 제네릭으로 선언
function useForm<T>(initialValues: T, validate: (values: T) => Errors<T>) {
  const [values, setValues] = useState<T>(initialValues);

  const [errors, setErrors] = useState<Errors<T>>();

  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const { name, value } = e.target;

    setValues((prev) => ({
      ...prev,
      [name]: value,
    }));
  };

  const handleSubmit = (callback: (values: T) => void) => {
    const validationErrors = validate(values);

    setErrors(validationErrors);

    const hasError = Object.keys(validationErrors).length > 0;

    if (!hasError) {
      callback(values);
    }
  };

  return {
    values,
    errors,
    handleChange,
    handleSubmit,
  };
}
export default useForm;

 

import useForm from "../hooks/useForm";

type LoginForm = {
  email: string;
  password: string;
};
const initialValues: LoginForm = {
  email: "",
  password: "",
};
const validate = (values: LoginForm) => {
  const errors: Partial<LoginForm> = {};

  if (!values.email) {
    errors.email = "이메일 입력";
  }

  if (values.password.length < 6) {
    errors.password = "6자 이상";
  }

  return errors;
};
function Login() {
  const { values, errors, handleChange, handleSubmit } = useForm(initialValues, validate);
  const onSubmit = (values: LoginForm) => {
    console.log(values);
  };

  function handleLogin() {
    handleSubmit(onSubmit);
  }
  return (
    <>
      <label>이메일</label>
      <input type="email" name="email" value={values.email} onChange={handleChange} />
      <p>{errors?.email}</p>

      <label>패스워드</label>
      <input type="password" name="password" value={values.password} onChange={handleChange} />
      <p>{errors?.password}</p>
      <button onClick={handleLogin}>로그인</button>
    </>
  );
}

export default Login;
반응형

'React' 카테고리의 다른 글

⚽️Zustand  (0) 2025.12.01
🍏 React Hook  (0) 2025.10.24

댓글