일반 HTML 폼의 동작 방식
일반적인 HTML 폼에서는 input 요소가 자체적으로 값을 내부에 보관하며, 제출 버튼을 클릭하면 폼 데이터가 함께 전송됩니다.
예제
<!DOCTYPE html>
<html>
<head>
<title>Form Example</title>
</head>
<body>
<form>
<label>
User Name:
<input type="text" name="username" />
</label>
<input type="submit" value="Submit Form" />
</form>
</body>
</html>위 예제에는 username이라는 간단한 입력 필드가 있으며, 폼이 전송될 때 해당 값을 받아올 수 있습니다. HTML 폼의 기본 동작은 새로운 페이지로 이동하는 것, 즉 폼 전송 결과 페이지로 네비게이션하는 것입니다.
하지만 폼 전송을 처리하는 자바스크립트 핸들러 함수를 활용하면 더 큰 이점을 얻을 수 있습니다. 이 함수 안에서 폼 데이터의 유효성을 검증할 수 있고, 검증 결과를 사용자에게 즉각적인 피드백으로 전달할 수 있기 때문입니다.
React의 제어 컴포넌트(Controlled Components)
React는 제어 컴포넌트(controlled components)라고 불리는 기법으로 폼 전송을 처리합니다.
HTML에서와 마찬가지로 input, textarea 같은 요소들은 자체적인 상태를 가지며 사용자의 입력에 따라 스스로 업데이트됩니다. 반면 React에서는 이렇게 변경 가능한 값들을 state 객체로 관리합니다.
다음은 React의 제어 컴포넌트 방식으로 username 필드를 처리하는 예제입니다.
class UserForm extends React.Component {
constructor(props) {
super(props);
this.state = {username: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({username: event.target.value});
}
handleSubmit(event) {
console.log('username: ' + this.state.username);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.username} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}여기서는 onChange 핸들러 함수가 상태(state)의 username 필드를 업데이트합니다. 폼이 전송되면 handleSubmit이 호출되어 브라우저 콘솔에 제출된 사용자 이름을 출력하고, event.preventDefault()를 통해 기본적인 페이지 이동 동작을 막습니다.
다양한 종류의 제어 컴포넌트
제어 방식으로 다룰 수 있는 컴포넌트는 textarea, select 태그, 라디오 버튼 등도 있습니다. 반면 파일(file) 타입 입력처럼 본질적으로 읽기 전용이며 폼 전송 시점에만 값을 얻어오는 비제어 컴포넌트(uncontrolled components)도 존재합니다.
하나의 함수로 여러 입력 필드 처리하기
입력 필드가 많아지면 필드마다 개별 핸들러를 만드는 대신, 아래처럼 계산된 속성명(computed property name)을 활용해 하나의 자바스크립트 함수로 여러 입력을 처리할 수 있습니다.
handleInputChange(event) {
const value = event.target.value;
const name = event.target.name;
this.setState({
[name]: value
});
}이 방식에서는 input 요소의 name 속성값이 곧 state의 키가 되므로, 코드 중복 없이 깔끔하게 여러 필드를 관리할 수 있습니다.
주의 사항과 서드파티 라이브러리 활용
제어 입력의 value가 null이 되면 예상치 못한 동작이 발생할 수 있습니다. 따라서 state 초기화 단계에서 각 필드에 기본값을 설정해 null 값을 피하는 것이 좋습니다.
규모가 있는 애플리케이션에서 폼 처리를 더 체계적으로 하고 싶다면 Formik 같은 서드파티 라이브러리를 활용하는 것도 좋은 선택입니다. Formik을 사용하면 유효성 검사, 사용자 피드백 처리 등을 간편하게 구현할 수 있습니다.