Javascript/React

Form 다루기

kyoulho 2024. 7. 13. 18:11

서버에서 HTML을 생성해 웹 브라우저 쪽에 전송하는 전통 방식의 웹 개발에서는 사용자에게 데이터를 받을 때 <form> 요소를 사용한다. 이때 폼 요소는 method 속성에 HTTP 메서드를 설정하고, action 속성에는 폼 데이터를 전송한 뒤 전환할 화면의 URL을 설정하는 방식으로 사용한다. 만일 method 설정값이 POST 라면 폼 데이터를 암호화하는 다음 3가지 방식 중 하나를 encType 속성에 설정한다.

  1. application/x-www-form-urlencoded(기본값)
  2. multipart/form-data
  3. text/plan

하지만 리액트와 같은 SPA 방식은 백엔드가 API 방식으로 동작하므로 굳이 폼 요소와 속성등을 설정할 필요가 없다. 다만 관습적으로 사용자 입력을 받는 부분을 <form> 요소로 구현한다.

버튼 이벤트 예제

import type {FormEvent} from 'react'
... 생략 ...
const onSubmit = (e: FormEvent<HTMLFormElement>) => {}
<form onSubmit={onSubmit}>
	<input type="submit" value="버튼_텍스트" />
</form>

브라우저는 onSubmit 이벤트가 발생하면 <form> 이 있는 웹 페이지를 다시 렌더링 한다. 이 때문에 onSubmit을 구현할 때는 반드시 e.preventDefault()를 호출해 웹페이지가 다시 렌더링 되지 않도록 해야한다.
 

FormData 클래스

FormData 클래스는 JavaScript에서 제공하는 인터페이스로, 웹 애플리케이션이 서버로 데이터를 전송할 때 HTML 폼의 데이터와 동일한 형식으로 데이터를 쉽게 구성할 수 있게 한다.

생성자

  • FormData(): 빈 FormData 객체를 생성한다.
  • FormData(form): 주어진 HTMLFormElement 객체로부터 데이터를 초기화한다.

주요 메서드

  • append(name, value, filename): 폼 데이터에 새로운 키-값 쌍을 추가한다. 파일을 추가할 경우 filename을 지정할 수 있다.
  • delete(name): 주어진 이름의 모든 키-값 쌍을 삭제한다.
  • get(name): 주어진 이름의 첫 번째 값을 반환한다.
  • getAll(name): 주어진 이름의 모든 값을 배열로 반환한다.
  • has(name): 주어진 이름의 키가 존재하는지 여부를 확인한다.
  • set(name, value, filename): 주어진 이름의 값을 업데이트하거나 존재하지 않으면 새로 추가한다.

 

Form 사용 예제

import type {ChangeEvent, FormEvent} from 'react'
import {useCallback, useState} from 'react'
import {Title} from '../components'
import {Input} from '../theme/daisyui'

type FormType = {
  name: string
  email: string
}
export default function FormExample() {
  const [form, setForm] = useState<FormType>({name: '', email: ''})

  const onSubmit = useCallback(
    (e: FormEvent<HTMLFormElement>) => {
      e.preventDefault()
      alert(JSON.stringify(form, null, 2))
    },
    [form]
  )

  const onChangeName = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setForm(form => ({...form, name: e.target.value}))
  }, [])

  const onChangeEmail = useCallback((e: ChangeEvent<HTMLInputElement>) => {
    setForm(form => ({...form, email: e.target.value}))
  }, [])

  return (
    <section className={'mt-4'}>
      <Title>BasicForm</Title>
      <div className={'flex justify-center mt-4'}>
        <form onSubmit={onSubmit}>
          <div className={'form-control'}>
            <label className={'label'} htmlFor={'name'}>
              <span className={'label-text'}>Username</span>
            </label>
            <Input
              value={form.name}
              onChange={onChangeName}
              id={'name'}
              type={'text'}
              placeholder={'enter your name'}
              className={'input-primary'}
            />
          </div>
          <div className={'form-control'}>
            <label className={'label'} htmlFor={'email'}>
              <span className={'label-text'}>email</span>
            </label>
            <Input
              value={form.email}
              onChange={onChangeEmail}
              id={'email'}
              type={'email'}
              placeholder={'enter your email'}
              className={'input-primary'}
            />
          </div>
          <div className={'flex justify-center mt-4'}>
            <input
              type={'submit'}
              value={'SUBMIT'}
              className={'w-1/2 btn btn-sm btn-primary'}
            />
            <input
              type={'button'}
              defaultValue={'CANCEL'}
              className={'w-1/2 ml-4 btn btn-sm'}
            />
          </div>
        </form>
      </div>
    </section>
  )
}