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개를 유지하기 위한 방어코드를 추가했습니다
- 그렇지 않을경우 스프레드(…) 연산자를 통해 값만 복사한 새로운 배열에서 해당 인덱스를 제거합니다.
- MDN.Array.prototype.splice()
- MDN.Array.prototype.filter()를 사용할 수도 있습니다
- 이후 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를 덮어씌웁니다