React useInput hook으로 유효성 검사하기

서나무·2022년 12월 16일
0

React

목록 보기
4/5
post-thumbnail

사용자의 입력을 받고, 유효성 검사를 해야된다면 작성해야하는 코드량이 엄청 늘어난다.

import { useState, useEffect } from 'react';

export default function App() {
  // 사용자가 입력한 값을 담을 state
  const [email, setEmail] = useState('');
  
  // input이 변경되면 값을 email에 저장
  const onChangeEmail = (e) => {
    setEmail(() => e.target.value);
  };

  // email 유효성 결과를 담을 state
  const [emailValid, setEmailValid] = useState('');

  // email 유효성 검사 함수
  const emailRule = (v = '') => {
    if (v === '') return;
    if (!v.includes('@')) {
      return '형식이 올바르지 않습니다.';
    }
  };

  // email이 변경되면 유효성 검사
  useEffect(() => {
    if (!email) return;
    setEmailValid(() => emailRule(email));
  }, [email]);

  return (
    <div>
      <div>
        <label htmlFor='email'>이메일</label>
        <input
          id='email'
          type='text'
          value={email}
          onChange={onChangeEmail}
          placeholder='email@example.com'
        />
        <p style={{ color: 'red' }}>{emailValid}</p>
      </div>
      <button>Sing up</button>
    </div>
  )
}

만약 여기서 비밀번호도 입력받으면 어떻게 될까? 말해 뭐해? 코드가 2배가 된다.

Input Component

일단 iuput 태그를 컴포넌트로 만들자!

import React from "react";

const Input = ({
  id = Math.floor(Math.random() * 10000 + 1), // random 아이디 부여
  type = 'text',
  value = '',
  onChange,
  label = '',
  placeholder = '',
  disabled = false,
  valid = '', // 유효성 검사 결과
}) => {
  return (
    <div>
      <div>
        <label htmlFor={id}>{label}</label>
      </div>
      <input
        id={id}
        type={type}
        value={value}
        onChange={onChange}
        placeholder={placeholder}
        disabled={disabled}
      />
      <p style={{color: 'red'}}>{valid}</p>
    </div>
  );
};

export default React.memo(Input);

React.memo를 사용했는데, props가 변경되지 않으면 컴포넌트를 재렌더링 하지 않도록 최적화를 한 것이다.

useInput hook

이제 state와 유효성 검사 관련 로직을 hook으로 분리해보자.

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

// 초기 값, 유효성 검사 함수를 받음
const useInput = (initValue = '', rule) => {
  const [value, setValue] = useState(initValue);
  const [valid, setValid] = useState('');
  const onChange = useCallback((e) => {
    setValue(() => e.target.value);
  }, []);
  // value가 변경되면 유효성 검사하기
  useEffect(() => {
    if (rule) {
      setValid(() => rule(value));
    }
  }, [value]);
  return {
    value,
    setValue,
    onChange,
    valid,
  };
};

export default useInput;

Input + useInput

이제 Input 컴포넌트와 useInput hook을 사용해서 코드를 간결하게 작성해보자.

// Component
import Input from '../components/form/Input';

// hook
import useInput from '../hooks/useInput';

export default function App() {
  const {
    value: email,
    valid: validEmail,
    onChange: onChangeEmail,
  } = useInput('', emailRule);
  return (
    <div>
      <Input
        label='이메일'
        value={email}
        onChange={onChangeEmail}
        valid={validEmail}
        placeholder='email@example.com'
      />
      <button>Sing up</button>
    </div>
  );
}

const emailRule = (v = '') => {
  if (v === '') return;
  if (!v.includes('@')) {
    return '형식이 올바르지 않습니다.';
  }
};

input이 여러 개가 생겨도 코드가 2배로 늘어날 일은 없어졌다.

profile
주니어 프론트엔드 개발자

0개의 댓글