HTML 폼 엘리먼트는 폼 엘리먼트 자체가 내부 상태를 가지기 때문에, React의 다른 DOM 엘리먼트와 다르게 동작합니다. 폼을 제출하면 새로운 페이지로 이동하는 기본 HTML 폼 동작을 수행하는 것이 기본이며, 대부분의 경우 JavaScript 함수로 폼의 제출을 처리하고 사용자가 폼에 입력한 데이터에 접근하도록 제어합니다.
React에서는 변경할 수 있는 state가 일반적으로 컴포넌트의 state 속성에 유지되며 setState() 혹은 useState()에 의해 업데이트됩니다. 따라서 해당 <input>
에 onChange
속성과 <form>
에 onSubmit
속성을 통해서 state를 업데이트하고 관리함을 통하여 다른 UI 엘리먼트에 input의 값을 전달하거나 다른 이벤트 핸들러에서 값을 재설정할 수 있습니다.
공식 문서를 통하여 Html과의 차이점과 React 환경에서 이를 활용하고 computed property name을 통한 state 간소화를 배울 수 있습니다.
function NameForm (props) {
const [value, setValue] = React.useState('');
function handleChange(event) {
setValue(event.target.value);
}
function handleSubmit(event) {
event.preventDefault();
alert('A name was submitted: ' + value);
}
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
ReactDOM.render(
<NameForm />,
document.getElementById('root')
);
Formik은 React Native에서 컴포넌트를 빌드하기 위한 React 구성 요소 및 hooks의 작은 그룹입니다. 설치를 통해서 유효성 검사, 방문한 필드 추적 및 폼 제출 처리와 같은 절차를 간소화하고 제어 컴포넌트 및 state 관리에 기초하여 활용할 수 있습니다.
npm install formik --save
npm install yup --save
import React from 'react';
import { useFormik } from 'formik';
const SignupForm = () => {
// 데이터 형식에 맞추어 초기화하여 react에서 초기 렌더링 시 발생할 수 있는 에러를 방지합니다.
const formik = useFormik({
initialValues: {
firstName: '',
lastName: '',
email: '',
},
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
onChange={formik.handleChange}
value={formik.values.firstName}
/>
<label htmlFor="lastName">Last Name</label>
<input
id="lastName"
name="lastName"
type="text"
onChange={formik.handleChange}
value={formik.values.lastName}
/>
<label htmlFor="email">Email Address</label>
<input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
value={formik.values.email}
/>
<button type="submit">Submit</button>
</form>
);
};
useFormik hook은 formik변수에 폼의 상태와 여러가지의 helper 메소드를 리턴합니다. 대표적으로 다음과 같은 3가지 메서드가 있습니다.
<input>
, <select>
또는 <textarea>
에 전달하는 change핸들러<input>
의 현재 value이 메서드를 활용하여 기존 Html 형식으로 핸들링했던 방식과 동일하게 이를 컨트롤 가능하며, 초기값에 설정한 key 값과 동일하게 설정하므로 일치하는 ID 및 이름 HTML 특성을 전달합니다. 따라서, 동일한 이름(email -> formik.values.email)을 사용하여 해당 input에 액세스합니다.
const [values, setValues] = React.useState({});
const handleChange = event => {
setValues(prevValues => ({
...prevValues,
// 업데이트 할 `values`의 키를 formik에게 전달하기 위해 name prop을 사용
[event.target.name]: event.target.value
});
}
<input>
의 name을 기반으로 한 ES6의 computed property name 구문을 사용하고 있습니다.기존 값과 갱신 값을 state로 관리합니다.
기본적인 Html의 제한점은 크게 3가지 있습니다.
첫째, 브라우저에서만 작동하기에 React Native 환경에서 제약이 있습니다.
둘째, 지정 사용자에게 꼭 맞는 오류 메세지를 표시하는 것은 어렵거나 불가능합니다.
셋째, 동작에 있어서 버벅거림과 이상함이 있습니다.
Formik을 통하여 양식의 값뿐만 아니라 양식의 검증 및 오류 메시지도 추적 가능합니다. JS로 검증을 추가하려면 유효성 검증 함수를 선언하고 useFormik() Hook에 이를 전달하여 검증을 하는 것이 가능합니다. 이 때 유효성 검증 함수는 values와 initialValues와 똑같은 모양의 오류 객체를 만들어 냅니다.
// 유효성 검증 함수
// values와 initialValues와 똑같은 모양의 오류 객체 리턴
const validate = values => {
const errors = {};
if (!values.firstName) {
errors.firstName = '필수 작성 항목입니다';
} else if (values.firstName.length > 15) {
errors.firstName = '15자 이내로 작성해주세요';
}
if (!values.lastName) {
errors.lastName = '필수 작성 항목입니다';
} else if (values.lastName.length > 20) {
errors.lastName = '20자 이내로 작성해주세요';
}
if (!values.email) {
errors.email = '필수 작성 항목입니다';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = '유효하지 않은 이메일 양식입니다';
}
return errors;
};
const SignupForm = () => {
const formik = useFormik({
initialValues: {
firstName: '',
lastName: '',
email: '',
},
validate,
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
return (
<form onSubmit={formik.handleSubmit}>
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.firstName}
/>
// 유효성 메세지 부분
{formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
<label htmlFor="lastName">Last Name</label>
<input
id="lastName"
name="lastName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.lastName}
/>
// 유효성 메세지 부분
{formik.touched.lastName && formik.errors.lastName ? (
<div>{formik.errors.lastName}</div>
) : null}
<label htmlFor="email">Email Address</label>
<input
id="email"
name="email"
type="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
/>
// 유효성 메세지 부분
{formik.touched.email && formik.errors.email ? (
<div>{formik.errors.email}</div>
) : null}
<button type="submit">Submit</button>
</form>
);
};
또한, 사용에 있어서 Yup이라는 추가적인 라이브러리를 통하여 보다 코드를 간결화하는 것이 가능합니다. 간편하게 유효성 검증에 대한 함수를 대체할 수 있고
npm install yup --save
const formik = useFormik({
initialValues: {
firstName: '',
lastName: '',
email: '',
},
// 안으로 들어가버린 유효성 검증 함수, 보다 간결해진 코드!
validationSchema: Yup.object({
firstName: Yup.string()
.max(15, 'Must be 15 characters or less')
.required('Required'),
lastName: Yup.string()
.max(20, 'Must be 20 characters or less')
.required('Required'),
email: Yup.string().email('Invalid email address').required('Required'),
}),
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
getFieldProps() 메소드를 통하여 공통 사항에 대한 코드 볼륨을 줄일 수 있습니다.
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.firstName}
/>
{formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
type="text"
{...formik.getFieldProps('firstName')}
/>
{formik.touched.firstName && {formik.touched.firstName && formik.errors.firstName ? (
<div>{formik.errors.firstName}</div>
) : null}
onBlur, onFocus 이벤트
Json Object 관련 method
React Context