FrontEnd

[React🍇] <datalist>로 이메일 자동 완성 기능 구현하기

머털박사 2022. 8. 30. 17:03

 

SPOTV NOW 회원가입 페이지 UI

해당 포스팅은 react에서 datalist 태그를 사용해서 이메일 자동 완성 기능을 구현하는 방법에 대해 다룹니다.

SPOTV NOW 회원가입 페이지에 본 이메일 자동완성 기능이 인상 깊어서 진행중인 프로젝트에 적용해봤다.

구현 방법

  1. 자주 사용하는 이메일 리스트를 미리 정의한다.
  2. input value와 Email List 두 개를 useState로 등록한다.
  3. input에 onChange 이벤트를 등록한다.
    • input value가 자주 쓰는 이메일 값과 합쳐져서 Email List 를 만든다.
    • Email List를 순회하여태그의 value로 넣어준다.
  4. 선택한값을 input 값에 넣어준다.

<datalist> 란 무엇일까

<label for="email-choice">email:</label>
<input list="emailList" id="email-choice" name="email-choice" />

<datalist id="emailList">
    <option value="test@gmail.com">
    <option value="test@naver.com">
    <option value="test@daum.net">
    <option value="test@hanmail.net">
    <option value="test@yahoo.com">
</datalist>

이메일 자동 왼성 로직을 구현하기 위해서는 <datalist>라는 조금 생소한 태그를 사용한다. <option> 을 담는 태그로 <input>에 타이핑을 하면 그 밑에 추천하는 옵션이 자동으로 나타낸다. 해당 옵션을 선택하면 <input>의 값에 반영된다. 이 태그를 사용하기 위해서는 input의 list 속성값과 datalist의 id 속성값을 일치시켜야한다. 해당 태그를 사용하면 js로 적어야하는 코드가 획기적으로 줄어든다.

자주 사용하는 이메일 리스트 선언과 html 마크업

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

const EmailInput = () => {
  const frequencyEmails = [
    '@naver.com',
    '@gmail.com',
    '@daum.net',
    '@hanmail.net',
    '@yahoo.com',
    '@outlook.com',
    '@nate.com',
    '@kakao.com',
  ];

  return (
    <>
            <label>이메일</label>
            <input 
                list="emails"
        placeholder="이메일을 입력하세요"
            />
      <datalist id="emails">
      </datalist>
            <input type="submit">
    </>
  );
};

export default EmailInput;

자주 사용하는 이메일 string array을 미리 선언한다. 해당 array는 나중에 map 메서드를 사용해서 <option> 태그의 값으로 사용된다.

UseState로 상태관리 값 선언

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

const EmailInput = () => {
    const [emailValue, setEmailValue] = useState("");
  const [emailList, setEmailList] = useState<string[]>([]);

  const frequencyEmails = [
    '@naver.com',
    '@gmail.com',
    '@daum.net',
    '@hanmail.net',
    '@yahoo.com',
    '@outlook.com',
    '@nate.com',
    '@kakao.com',
  ];

    const onChangeEmail = (e: ChangeEvent<HTMLInputElement>) => {
    setEmailValue(e.target.value);
    const userEmails = frequencyEmails.map((email) =>
      e.target.value.includes('@')
        ? e.target.value.split('@')[0] + email
        : e.target.value + email
    );
    setEmailList(userEmails);
  };

  return (
    <>
            <label>이메일</label>
            <input 
                list="email"
        value={emailValue}
        placeholder="이메일을 입력하세요"
        onChange={onChangeEmail}
            />
      <datalist id="email">
        {emailList &&
          emailList.map((email, idx) => <option value={email} key={idx} />)}
      </datalist>
            <input type="submit">
    </>
  );
};

export default EmailInput;

useState로 상태 관리해줄 값은 두 가지다.

첫 번째로 input value를 입력받는 값, 두 번째는 (input value + 자주 사용하는 이메일) 조합의 string array다. 해당 값을 사용하는 로직은 input에 onChange 이벤트로 할당한다.

const onChangeEmail = (e: ChangeEvent<HTMLInputElement>) => {
    setEmailValue(e.target.value);
    const userEmails = frequencyEmails.map((email) =>
      e.target.value.includes('@')
        ? e.target.value.split('@')[0] + email
        : e.target.value + email
    );
    setEmailList(userEmails);
  };

일단 현재 타이핑하는 값을 바로 email value로 반영한다. 이후에 자주 사용하는 이메일 도메인 값을 순회하면서 e.target.value에 이메일 도메인 값을 더 한다.

이 때 예외 패턴이 있다. 만약 유저가 option 값을 선택하지 않고 끝까지 타이핑 할 경우이다. 만약 예외 패턴을 생각하지 않고 코드를 적용시키면 도메인 두 개가 붙는 현상이 생긴다. 예를 들어 test@gmail.com 라고 유저가 적은 경우 test@gmail.com@gmail.com 라는 값이 option의 value에 할당되는 것이다.

이를 해결하기 위해 만약 e.target.value에 ‘@’가 포함된 경우 e.target.value 를 @로 나눠서 앞에 있는 값만 가져온 후 다시 도메인과 연결한다. 이렇게 순회한 값을 setEmailList에 다시 할당한다.

         <datalist id="email">
        {emailList &&
          emailList.map((email) => <option value={email} key={email} />)}
      </datalist>

html으로 emailList가 존재하는 경우 map으로 순회하여 <option>의 value로 할당한다.

결과물

완성~