HTML Form에 대하여

나는 React, Next를 주로 사용한다. 그러다 보니 상태와 리렌더링에 대해 늘 고민을 하며 개발을 하고 있다. 그러다 Form을 구성하면서 의구심이 들었다.

React를 사용하면 hooks를 사용할 것이고, 상태를 구성하기 위해 useState를 사용한다. 이러면 일반적인 Form구성은 아래 방법으로 구성한다.

const Form = () => {
	const [name, setName] = useState('')
	const [password, setPassword] = useState('')

	const onNameChange = (event) => {
		setName(event.currentTarget.value)
	}
	const onPasswordChange = (event) => {
		setPassword(event.currentTarget.value)
	}
	const onSubmit = (event) => {
		event.preventDefault()

		// 어떠한 전송이 실행되는 부분...
	}

	return (
		<form onSubmit={onSubmit}>
			<input
				value={name}
				onChange={onNameChange}
				type="text"
			/>
			<input
				value={password}
				onChange={onPasswordChange}
				type="password"
			/>
			<button>전송</button>
		</form>
	)
}

늘 구성하는 Form이지만, useState구성이 불편했다. <input />Change Event가 발생할 때마다 위 컴포넌트를 리렌더링되는 점이 굉장히 마음에 들지 않았다.

여기서 개선하는 방법이 해당 <input />을 컴포넌트로 묶은 후 debounce를 적용하는 방법을 많이 떠올릴 수 있겠지만, 그래도 Change Event가 일어나면 리렌더링이 된다.

리렌더링되니 상태를 빼버리자

위에서 일어나는 리렌더링을 방지하고 싶었다. 그래서 상태를 제거했다. 그러면 해당 Form의 데이터를 가지고 오는 방법을 바꿔야 했다. HTML이 제공하는 기능들을 최대한 활용해서 이를 해결해보았다.

const Form = () => {
	const onSubmit = (event) => {
		event.preventDefault()

		const data = new FormData(event.currentTarget)

		// 어떠한 전송이 실행되는 부분...
	}

	return (
		<form onSubmit={onSubmit}>
			<input name="name" type="text" />
			<input name="password" type="password" />
			<button>전송</button>
		</form>
	)
}

React가 없던 시절, POST를 실행하기 위해 HTML에는 각 입력부분에 이름을 추가할 수 있었다. 이 이름으로 서버는 데이터의 유형을 파악할 수 있었다. 그리고 Submit Evenv는 해당 이벤트가 발생한 <Form />을 받을 수 있다.

마지막으로 해당 태그의 안에는 명명된 입력창들이 있고, 그 입력창들은 사용자가 입력한 값들을 이름과 같이 가지고 있다. 이것을 활용하면, 상태를 사용하지 않고 Form 구성이 가능하다.

의문점

❓ 입력창에 입력되는 값들이 상태와 달라지는 경우가 발생할 수 있지 않나요?

애초에 입력되는 값들이 상태에 담길 필요가 없다. 그리고 상태의 변화는 입력되는 순간이 아닌, Submit 순간에 발생하는 것이 맞다고 본다.

❓ 입력되는 값에 대한 Error 핸들링은 어떻게 하나요?

상태를 Form에 담아 넘길 Data 구성에 사용을 안하는 것이지, 다른 용도로 사용을 안하는 것이 아니다. Input을 독립된 컴포넌트로 구성하여 발생하는 Event에 따라 Error에 대한 상태를 구성할 수 있다.

❓ 최초 입력된 값에 대한 방법이 있나요?

defaultValue