React.js & Next.js

리액트에서 다중의 동적 폼 처리하기

준희닷 2023. 6. 15. 20:04

들어가며

프론트엔드로 개발하게 될 경우, 정적으로 사전에 생성된 폼 데이터를 다루기도 하지만, 동적으로 추가하거나 제거 및 수정이 필요한 폼을 만들어야 하는 경우가 생깁니다.

 

스타일링 코드를 제거하고 자바스크립트 코드 위주로 동적 폼 처리에 대한 기본적인 흐름을 파악합니다.

예시 [wanted] 동적 폼 처리 뷰

원티드의 동적 폼 예시

코드

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

function DynamicFormComponent() {
  const [formFields, setFormFields] = useState([{ name: '', value: '' }]);

  const handleAddFields = () => {
    const values = [...formFields, { name: '', value: '' }];
    setFormFields(values);
  };

  const handleRemoveFields = (index: number) => {
    if (formFields.length === 1) {
      alert('At least one form must remain');
      return;
    }
    const values = [...formFields].splice(index, 1);
    setFormFields(values);
  };

  const handleInputChange = (index: number, e: React.ChangeEvent<HTMLInputElement>) => {
    const values = [...formFields];

    if (e.target.name === 'name') {
      values[index].name = e.target.value;
    } else {
      values[index].value = e.target.value;
    }
    setFormFields(values);
  };

  const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    console.log(formFields);
  };

  useEffect(() => {
    console.log('formFields changed:', formFields);
  }, [formFields]);

  return (
    <form onSubmit={handleSubmit} style={{ padding: '2%' }}>
      {formFields.map((field, index) => (
        <div key={index} style={{ marginBottom: 5 }}>
          <input
            type='text'
            placeholder='Field name'
            name='name'
            value={field.name}
            onChange={(e) => handleInputChange(index, e)}
            style={{ marginRight: 10 }}
          />

          <input
            type='text'
            placeholder='Field value'
            name='value'
            value={field.value}
            onChange={(e) => handleInputChange(index, e)}
            style={{ marginRight: 10 }}
          />

          <button type='button' onClick={() => handleRemoveFields(index)}>
            Remove
          </button>
        </div>
      ))}

      <button
        type='button'
        onClick={() => handleAddFields()}
        style={{ marginTop: 10, marginRight: 10 }}
      >
        Add Field
      </button>

      <button type='submit'>Submit</button>
    </form>
  );
}

export default DynamicFormComponent;

함수 설명

handleAddFields

  const handleAddFields = () => {
    const values = [...formFields, { name: '', value: '' }];
    setFormFields(values);
  };
  • 필드를 동적으로 추가합니다
  • useState로 관리하고 있는 formFields를 스프레드(…)연산자를 통해 값만 복사하여, 빈 객체 ( {name:’’, value: ‘’} )를 추가합니다
  • 이후 setState를 통해 values를 덮어씌웁니다

handleRemoveFields

  const handleRemoveFields = (index: number) => {
    if (formFields.length === 1) {
      alert('At least one form must remain');
      return;
    }
    const values = [...formFields].splice(index, 1);
    setFormFields(values);
  };
  • formField를 최소한 1개를 유지하기 위한 방어코드를 추가했습니다
  • 그렇지 않을경우 스프레드(…) 연산자를 통해 값만 복사한 새로운 배열에서 해당 인덱스를 제거합니다.
  • 이후 setState를 통해 values를 덮어씌웁니다

handleInputChange

  const handleInputChange = (index: number, e: React.ChangeEvent<HTMLInputElement>) => {
    const values = [...formFields];

    if (e.target.name === 'name') {
      values[index].name = e.target.value;
    } else {
      values[index].value = e.target.value;
    }
    setFormFields(values);
  };
  • if 조건문을 통해 분기를 나눴습니다
    • e.target.name 이 ‘name’ 일 경우 해당 index에 따른 value값을 객체의 name 속성에 재할당합니다
    • e.target.name 이 ‘value’ 일 경우 해당 index에 따른 value값을 객체의 value 속성에 재할당합니다
  • 이후 setState를 통해 values를 덮어씌웁니다

결과 보기