React로 양식(form) UI 구현하기
Aug 1, 2020 · 4 min read



양식(form)은 웹애플리케이션에서 사용자로 부터 데이터를 입력 받기 위해서 필수적인 기능입니다. 이번 포스트에서는 비빌번호를 변경을 위한 간단한 리액트(React) 컴포넌트를 구현해보겠습니다.

JSX 기본 마크업

먼저 하나의 입력란과 제출 버튼으로 구성된 간단한 양식에 대한 마크업을 작성해보겠습니다. <form/> 부모 엘리먼트 아래에 <input/><button/> 엘리멘트를 자식으로 추가합니다.

(본 포스트에서는 기능적인 부분에 초점을 맞출 것이기 때문에 CSS와 같은 시각적인 측면은 배재하도록 하겠습니다.)

import React from "react"

function PasswordUpdate() {
  return (
    <form>
      <input name="password" />
      <button type="submit">비밀번호 변경</button>
    </form>
  )
}

이 상태에서 버튼을 클릭해보면 화면만 깜빡이고 아무 것도 일어나지 않을 것입니다.

입력값 상태

사용자가 입력한 비밀번호를 React가 인지하고 통제할 수 있도록 해줘야 합니다. React의 useState() 훅(hook)을 사용하면 함수 컴포넌트에 간단하게 상태를 추가해줄 수 있습니다.

입력란에서 입력값이 바뀔 때 마다 발생하는 변경(change) 이벤트를 처리하기 위한 handleChange() 함수를 작성합니다. 그리고 입력란(<input/>)의 value 속성에 상태값을 설정하고, onChange 속성에 handleChange() 함수를 설정해줍니다.

useState 훅이 생소하신 분들은 관련 포스트를 참고 바랍니다.

import React, { useState } from "react"

function PasswordUpdate() {
  const [password, setPassword] = useState("")

  const handleChange = ({ target: { value } }) => setPassword(value)

  return (
    <form>
      <input
        type="password"
        name="password"
        value={password}
        onChange={handleChange}
      />
      <button type="submit">비밀번호 변경</button>
    </form>
  )
}

제출 이밴트 처리

제출 버튼을 클릭하면 양식(form)에서 제출(submit) 이벤트가 발생합니다. 이 이벤트를 처리하기 위한 handleSubmit() 함수를 작성하고, 양식(<form/>)의 onSubmit 속성에 설정해줍니다.

양식을 제출할 때는 기본적으로 브라우저에서 새로 고침이 일어나는데, SPA(single page application)에서는 필요가 없는 동작으로 event.preventDefault()로 방지합니다. 입력된 패스워드는 브라우저에 내장된 alert() 함수를 통해 알람창으로 띄우도록 하겠습니다.

import React, { useState } from "react"

function PasswordUpdate() {
  const [password, setPassword] = useState("")

  const handleChange = ({ target: { value } }) => setPassword(value)

  const handleSubmit = (event) => {
    event.preventDefault()
    alert(`변경된 패스워드: ${password}`)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="password"
        name="password"
        value={password}
        onChange={handleChange}
      />
      <button type="submit">비밀번호 변경</button>
    </form>
  )
}

중복 제출 방지

사용자가 양식에서 제출 버튼을 클릭하면 서버나 외부 API를 호출하는 경우가 많은데 어쩔 수 없이 약간의 지연이 발생하게 됩니다. 사용자가 현재 진행 중인 제출 이벤트 처리가 미처 종료되기 전에 제출 버튼을 또 클릭할 경우, 양식이 중복 제출되는 문제가 발생할 수 있습니다. 따라서 사용자가 제출 버튼을 클릭하지 마자, 제출 버튼을 비활성화 시켰다가, 이벤트 처리가 완료되었을 때, 제출 버튼을 다시 활성화 시켜주는 것이 안전합니다.

먼저 버튼의 활성화 여부를 관리하기 위한 disabled 상태를 추가하고, 제출 버튼(<button/>)의 disabled 속성에 설정해줍니다. 그리고 handleSubmit() 함수에서 disabled 상태값을 맨 처음에는 true로 변경하였다가 맨 마지막에는 false로 변경해줍니다. 마지막으로 제출 이벤트 처리 시 발생하는 지연을 시뮬레이션 하기 위해서 handleSubmit() 함수 내에서 일부로 1초 지연을 발생시킵니다.

import React, { useState } from "react"

function PasswordUpdate() {
  const [password, setPassword] = useState("")
  const [disabled, setDisabled] = useState(false)

  const handleChange = ({ target: { value } }) => setPassword(value)

  const handleSubmit = async (event) => {
    setDisabled(true)
    event.preventDefault()
    await new Promise((r) => setTimeout(r, 1000))
    alert(`변경된 패스워드: ${password}`)
    setDisabled(false)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="password"
        name="password"
        value={password}
        onChange={handleChange}
      />
      <button type="submit" disabled={disabled}>
        비밀번호 변경
      </button>
    </form>
  )
}

이제 제출 버튼을 클릭해보면 1초 간 버튼이 비활성된 후에 알람창이 뜨고, 알림창을 닫으면 버튼이 다시 활성화 될 것입니다.

양식 검증

일반적으로 양식에서 사용자가 잘못된 값을 입력하는 경우 입력값을 처리하지 않고 피드백을 줘야 합니다. 예제 양식에서는 8자리 이상의 비밀번호가 입력되었는지 검증하는 코드를 handleSubmit() 함수에 삽입하도록 하겠습니다.

import React, { useState } from "react"

function PasswordUpdate() {
  const [password, setPassword] = useState("")
  const [disabled, setDisabled] = useState(false)

  const handleChange = ({ target: { value } }) => setPassword(value)

  const handleSubmit = async (event) => {
    setDisabled(true)
    event.preventDefault()
    await new Promise((r) => setTimeout(r, 1000))
    if (password.length < 8) {
      alert("8자의 이상의 비밀번호를 사용하셔야 합니다.")
    } else {
      alert(`변경된 패스워드: ${password}`)
    }
    setDisabled(false)
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="password"
        name="password"
        value={password}
        onChange={handleChange}
      />
      <button type="submit" disabled={disabled}>
        비밀번호 변경
      </button>
    </form>
  )
}

이제 비밀번호를 입력하지 않거나, 8자보다 짧은 비밀번호를 입력하고 양식을 제출할 경우, 알람창에 에러 메세지가 표시될 것입니다.

입력란이 많은 양식의 경우에는 위와 같이 제출 버튼을 클릭할 때 뿐만 아니라, 하나의 입력란에 입력을 마치고 다음 입력란으로 넘어갈 때 피드백을 주는 편이 사용자 입장에서 더 나은 경험이 될 수 있습니다. 이렇게 실시간 입력값 검증이 필요한 경우에는 각 입력란에서 blur 이벤트가 발생할 때 입력값 검증을 처리해주면 됩니다.

전체 코드

본 포스트에서 작성한 코드는 아래에서 확인하고 직접 실행해보실 수 있습니다.

마치면서

이상으로 React를 사용해서 어떻게 양식 UI를 구현할 수 있는지 매우 간단한 예제를 통해서 살펴보았습니다. 실제 프로젝트에서 React로 좀 더 복잡한 양식을 구현해보면 처음에 생각보다 고려해야 부분이 많다는 것을 금방 느끼게 되실 겁니다. 다음 포스트에서는 커스텀 훅(hook)을 이용해서 이렇게 복잡해지는 코드를 분리하는 방법에 대해서 다뤄보도록 하겠습니다.






Engineering Blog  by Dale Seo