2021. 12. 30. 01:17ㆍReact, Javascript
React로 서비스를 개발하다보면 사용자 입력을 받아 처리하는 서식, 즉 form 형태를 많이 만들어야 한다.
대표적인 form으로는 모든 서비스에 거의 다 있는 로그인 기능이다.
아래는 React에서 Typescript 기반으로 작성한 단순한 로그인 form 예시다.
import React, { ReactElement } from 'react';
interface LoginForm {
email: string;
password: string;
}
export default function Login() {
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const handleSubmit = (values: LoginForm) => {
console.log('go login');
};
return(
<>
<form onSubmit={handleSubmit}>
<input value={email} handleChange={(e) =>
{setEmail(e.target.value)}} />
<input value={password} handleChange={(e) =>
{setPassword(e.target.value)}} />
<button type="submit">login</button>
</form>
</>
);
}
지금은 input이 두개뿐이여서 state를 세팅하는 로직이 handleChange 함수에 두개 들어가있다.
하지만 회원가입 화면이라면 어떨까?
우리는 똑같은 코드를 입력 칸만큼 해야하는 지옥에 빠져들게 된다.
로그인 화면도 단순하게 id, password를 입력하는 input 태그와
로그인 버튼만 만들면 다가 아니다.
id, password 입력이 정상적으로 이루어 졌는지 체크하는 로직이 필요하고
id가 글자제한이 있다면 제한글자까지만 써지게 하는 로직도 필요하다.
만약 id가 email 형태라면 해당 형식에 맞는지 체크해야하기도 한다.
이것이 앞선 예시처럼 회원가입 화면이였다면?
더욱 더 많은 체크로직으로 코드는 매우 복잡해질 것이다.
이 노가다 작업을 많이 개선해줄 Formik에 대해 알아보자.
1. Formik 소개
Formik은 React의 장황한 form을 3가지 측면에서 도와주는 작은 라이브러리다.
- form state 안팎에서 값 가져오기
- 유효성 검사 및 오류 메시지
- form submit 처리
현재 시점에 비슷한 라이브러리들과의 다운로드 수를 비교해보면 1위를 달리고 있다.
formik이 다른 라이브러리들에 비해 성능 측면이나 추론, 리펙토링에서 우위를 점하고 있다.
설치하기
yarn add formik
or
npm install formik
2. 기본 Formik 사용하기 ( /w Typescript )
Formik을 사용하지 않고 만들었던 로그인 화면을 유효성 검사를 도와는 yup라이브러리와 함께 개선해보았다.
import React, { ReactElement } from 'react';
import { Form, Formik, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
//유효성 검사를 위한 yup 라이브러리 기능을 변수에 담는다.
const ValidationSchema = Yup.object().shape({
email: Yup.string().email().required('email은 필수항목입니다.'),
password: Yup.string().required('password는 필수항목입니다.'),
});
//로그인에 사용될 변수의 타입을 정의한다.
interface LoginForm {
email: string;
password: string;
}
export default function Login() {
const handleSubmit = (values: LoginForm) => {
console.log(values);
};
<Formik
initialValues={{ email: '', password: '' }}
validationSchema={ValidationSchema}
onSubmit={handleSubmit}>
<Form>
<Field
name="email"
type="email"
placeholder="Email"
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
form={''}
/>
<ErrorMessage name="email" component="div" className="text-xs text-red-500 py-1" />
<Field
name="password"
type="password"
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
placeholder="Password"
/>
<ErrorMessage name="password" component="div" className="text-xs text-red-500 py-1" />
<button
className="bg-blueGray-800 text-white active:bg-blueGray-600 text-sm font-bold uppercase px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 w-full ease-linear transition-all duration-150"
type="submit">
Sign In
</button>
</Form>
</Formik>
);
}
이렇게 하면 setState를 입력란 마다 붙이지 않아도 되며
유효성 체크와 에러메시지까지 잡을 수 있다.
앞서 언급했듯이 이는 입력란이 많을 수록 더욱 빛을 바란다.
위부터 차분히 살펴보자
1) <Formik> 컴포넌트
이 컴포넌트에는 initialValues와 onSubmit은 필수 값이다.
initialValues는 form의 입력란에 들어갈 value의 초기값이다.
onSubmit은 제출 시에 실행될 함수다.
yup을 사용하면서 들어가는 속성값으로 validationSchema가 있다.
yup은 유효성 체크에 정말 뛰어난 라이브러리이다.
해당 기능들을 더 알고 싶다면 아래 문서를 참고하라.
2) <Form>, <Field> 컴포넌트
<Form>컴포넌트는 html에서 <form>태그와 비슷한 역할을 한다.
이 컴포넌트 아래 <Field>컴포넌트를 두고 props로 name을 initialValues의 키값으로 세팅하면
우리가 setState를 했던 것과 해당 값을 가져와서 유효성 검사를 하는 것이 모두 자동 설정된다.
3) <ErrorMessage> 컴포넌트
우리가 yup에서 정의했거나 미리 yup에서 정의해둔 에러메시지를 표시해주는 곳이다.
어떤 component에 메시지를 표시할 것인지와 className으로 스타일을 지정해 줄 수 있다.
3. Formik의 다양한 활용
위에서 예시로 든 코드는 Formik의 간단한 활용이였다.
이제 더 다양한 방법으로 Formik을 활용해 보자.
import React, { ReactElement } from 'react';
import { Form, Formik, Field, ErrorMessage, FormikProps } from 'formik';
import * as Yup from 'yup';
interface LoginForm {
email: string;
password: string;
checkbox: string;
radio: Array<string>;
}
const ValidationSchema = Yup.object().shape({
email: Yup.string().email().required('email은 필수항목입니다.'),
password: Yup.string().required('password는 필수항목입니다.'),
});
export default function FormikPractice() {
const handleSubmit = (values: LoginForm) => {
console.log(values);
};
return (
<Formik
initialValues={{ email: '', password: '', checkbox: '', radio: [] }}
validationSchema={ValidationSchema}
onSubmit={(data: LoginForm, { setSubmitting }) => {
setSubmitting(true);
handleSubmit(data);
setSubmitting(false);
}}>
{(props: FormikProps<LoginForm>) => {
const { values, touched, errors, handleBlur, handleChange, isSubmitting } = props;
return (
<Form>
<div className="relative w-full mb-3">
<label className="block uppercase text-blueGray-600 text-xs font-bold mb-2">Email</label>
<Field
name="email"
type="email"
placeholder="Email"
onChange={handleChange}
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
form={''}
/>
<ErrorMessage name="email" component="div" className="text-xs text-red-500 py-1" />
</div>
<div className="relative w-full mb-3">
<label className="block uppercase text-blueGray-600 text-xs font-bold mb-2">Password</label>
<Field
name="password"
type="password"
className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150"
placeholder="Password"
/>
<ErrorMessage name="password" component="div" className="text-xs text-red-500 py-1" />
</div>
<div className="relative w-full mb-3">
<Field name="checkbox" type="checkbox" value="formikcheckbox" />
</div>
<div className="relative w-full mb-3">
<Field name="radio" type="radio" value="formik1" />
<div>formik1</div>
<Field name="radio" type="radio" value="formik2" />
<div>formik2</div>
<Field name="radio" type="radio" value="formik3" />
<div>formik3</div>
<Field name="radio" type="radio" value="formik4" />
<div>formik4</div>
</div>
<div className="text-center mt-6">
<button
className="bg-blueGray-800 text-white active:bg-blueGray-600 text-sm font-bold uppercase px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 w-full ease-linear transition-all duration-150"
type="submit"
disabled={isSubmitting}>
Sign In
</button>
</div>
</Form>
);
}}
</Formik>
);
}
위는 Formik으로 활용할 수 있는 예시를 담은 코드이다.
몇가지 포인트를 살펴보면
1) FormikProps의 사용
2.번 예시에서 들었던 소스와 비교했을 때 가장 먼저 변한 것이 Formik 컴포넌트 아래 함수형태로 시작한 것이다.
이는 Form 컴포넌트 안에서 FormikProps를 활용하기 위한 것으로
소스에서 확인 할 수 있듯이 values, handleBlur, handleChange, isSubmitting 등을 가져다 쓸 수 있다.
2) 버튼 두번 클릭 방지
Formik을 쓸 때 편한 기능 중 하나인 두번 클릭 방지 기능이 있다.
isSubmitting을 button태그에 disabled에 달아두었다.
이를 submit함수에서 비동기 처리 전에 true로 세팅했다가 끝나면 false로 세팅하는 것을 볼 수 있다.
button에서 이 값을 참조하여 disable처리가 되어 두번 클릭을 방지 한다.
3) 다양한 input 활용
입력란은 단순 text input 태그만 존재하는 것이 아니다.
체크박스도 존재하고 라디오 버튼도 존재한다.
initialValues에 추가된 checkbox와 radio가 그 예시이다.
checkbox는 선택을 하면 값이 배열 형태로 온다. 선택을 하지 않으면 빈 string이 온다.
radio버튼은 만들어진 4개 중 선택한 값만 온다.
마무리
지금까지 Formik을 React-typescript에서 사용하는 방법에 대해 알아봤다.
Formik은 정말 form작성에 없어서는 안될 라이브러리이다.
설명에 언급하진 않았지만 이것을 활용하면 회원가입시 아이디중복 체크를 하는 서버통신 유효성 체크까지
추론이 쉽게 붙일 수 있다.
그 외 다양한 활용 방법들은 공식문서를 참고하자.
'React, Javascript' 카테고리의 다른 글
Typescript로 Node+Express API 서버 개발환경 세팅 (1) | 2022.02.07 |
---|---|
[React] 이미지 사용의 모든 것(feat. SVG, SVGO) (0) | 2022.01.14 |
[React] 상대경로 지옥에서 벗어나기 (craco) (1) | 2021.06.14 |
[React] 무작정 React 시작하기 (0) | 2021.04.03 |
TypeScript로 Stack 구현하기 (feat. 배열Array 사용하지 않기) (0) | 2021.01.24 |