커스텀 React Hook으로 폼 필드 처리하기

로그인 페이지를 만들 때와 마찬가지로, 회원가입 페이지를 만들기 전에 React에서 폼 필드를 처리하는 방법을 간소화해 보겠습니다. 로그인 컴포넌트에서는 사용자 이름과 비밀번호를 저장하기 위해 두 개의 상태 변수를 만들었습니다.

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");

그리고 상태를 설정하기 위해 다음과 같은 코드를 사용했습니다:

onChange={(e) => setEmail(e.target.value)}

이제 회원가입 페이지에서도 비슷한 작업을 할 텐데, 로그인 페이지보다 더 많은 필드가 있을 것입니다. 따라서 이 과정을 간소화하고, 모든 폼 관련 컴포넌트가 공유할 수 있는 공통 로직을 만드는 것이 합리적입니다. 또한 이는 React Hook의 가장 큰 장점인 컴포넌트 간 상태 로직 재사용을 소개하기에 좋은 기회입니다.

커스텀 React Hook 만들기

Change indicator src/lib/hooksLib.ts에 다음 내용을 추가하세요.

import { useState, ChangeEvent, ChangeEventHandler } from "react";

interface FieldsType {
  [key: string | symbol]: string;
}

export function useFormFields(
  initialState: FieldsType
): [FieldsType, ChangeEventHandler] {
  const [fields, setValues] = useState(initialState);

  return [
    fields,
    function (event: ChangeEvent<HTMLInputElement>) {
      setValues({
        ...fields,
        [event.target.id]: event.target.value,
      });
      return;
    },
  ];
}

커스텀 훅을 만드는 것은 매우 간단합니다. 사실, 우리는 앱 컨텍스트를 만들 때 이미 이 작업을 했습니다. 하지만 이번에는 이 훅이 어떻게 동작하는지 자세히 살펴보겠습니다:

  1. 커스텀 React 훅은 이름에 use라는 단어로 시작합니다. 따라서 우리 훅의 이름은 useFormFields입니다.

  2. 우리 훅은 폼 필드의 초기 상태를 객체로 받아서 fields라는 상태 변수로 저장합니다. 여기서 초기 상태는 폼 필드의 id를 키로, 사용자가 입력한 값을 값으로 가지는 객체입니다.

  3. 훅은 fields와 이벤트 객체를 기반으로 새로운 상태를 설정하는 콜백 함수를 배열로 반환합니다. 콜백 함수는 이벤트 객체를 받아서 event.target.id로 폼 필드의 id를, event.target.value로 값을 가져옵니다. 폼 엘리먼트의 경우, event.target.idForm.Group 엘리먼트에 설정된 controlId에서 가져옵니다:

    <Form.Group controlId="email">
      <Form.Label>Email</Form.Label>
      <Form.Control
        autoFocus
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
      />
    </Form.Group>
    
  4. 콜백 함수는 useState에서 얻은 setValues 함수를 직접 사용합니다. 따라서 onChange에서 사용자가 입력한 값을 받아서 setValues를 호출하여 fields의 상태를 업데이트합니다. { ...fields, [event.target.id]: event.target.value } 이 업데이트된 객체가 새로운 폼 필드 상태로 설정됩니다.

이제 이 훅을 Login 컴포넌트에서 사용할 수 있습니다.

커스텀 훅 사용하기

컴포넌트에서 커스텀 훅을 사용하려면 몇 가지 변경이 필요합니다.

Change indicator 먼저 src/containers/Login.tsx에서 훅을 가져옵니다.

import { useFormFields } from "../lib/hooksLib";

Change indicator 변수 선언을 교체합니다.

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");

Change indicator 다음 코드로 대체합니다.

const [fields, handleFieldChange] = useFormFields({
  email: "",
  password: "",
});

Change indicator validateForm 함수를 다음 코드로 교체합니다.

function validateForm() {
  return fields.email.length > 0 && fields.password.length > 0;
}

Change indicator handleSubmit 함수에서 Auth.signIn 호출을 다음 코드로 교체합니다.

await Auth.signIn(fields.email, fields.password);

Change indicator 두 개의 폼 필드를 교체합니다. 먼저 <Form.Control type="email">부터 시작합니다.

<Form.Control
  autoFocus
  size="lg"
  type="email"
  value={fields.email}
  onChange={handleFieldChange}
/>

Change indicator 마지막으로 패스워드 <Form.Control type="password">를 교체합니다.

<Form.Control
  size="lg"
  type="password"
  value={fields.password}
  onChange={handleFieldChange}
/>

useFormFields 훅을 사용하고 있습니다. 커스텀 React 훅을 이해하는 좋은 방법은 훅을 사용하는 부분을 훅 코드 자체로 대체하는 것입니다. 따라서 다음 코드 대신:

const [fields, handleFieldChange] = useFormFields({
  email: "",
  password: "",
});

useFormFields 함수의 코드를 상상해 보세요!

마지막으로, 커스텀 훅이 반환하는 함수를 사용해 필드를 설정합니다.

onChange = { handleFieldChange }

이제 회원가입 페이지를 다룰 준비가 되었습니다.