formikFrontend/리액트 개발 꿀팁2021. 9. 8. 20:43
Table of Contents
Formik?
- React로 웹을 만들다보면 우리는 사용자에게 다양한 인풋을 받게 된다.
- 이때 모든 인풋을 각각의 state로 관리하면 코드가 매우 지저분해질 수도 있다.
- Formik을 사용하면 이러한 form에 대한 state관리가 굉장히 편해진다!
(나는 리덕스로 dynamic form을 만드려고 삽질을 했었다..) - Formik은 리액트 폼의 세가지 어려운 부분을 쉽게 처리할 수 있도록 도와준다!
- form 상태의 안밖에서 값 가져오기
- 유효성 검증 및 에러 메시지
- 폼 제출 조작
- 우선, 아래 명령어를 이용하여 formik을 설치하자.
// npm
npm install formik --save
// yarn
yarn add formik
<Formik />
- form을 감싸며 form의 여러 상태를 관리해주는 컴포넌트로 볼 수 있다!
- formik은 유용한 몇가지 props를 form에 넘겨준다.
- Formik 컴포넌트 내에서 initialValues prop으로 초기 state를 json 형태로 지정할 수 있다.
- initialValues는 values라는 이름의 props로 접근할 수 있고 input의 name 필드에 key값을 써주고 onChange에 Formik에서 디폴트 props로 넘겨준 handleChange를 넣어주기만 하면 state에 있는 해당 key가 매핑되어 값이 바뀔 때마다 자동으로 state가 업데이트된다!
- onSubmit prop으로 submit이 되었을 때 처리할 일(함수, 비동기 통신 등등..)을 지정할 수 있고 첫번째 파라미터에 state가 들어간다. 그리고, handleSubmit이라는 props로 넘겨준다!
import React from 'react';
import { Formik } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{name: "처음 상태"}}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<input value={props.values.name} onChange={props.handleChange} name="name"/>
<button type="submit">변경된 상태 확인!</button>
</form>
)}
</Formik>
</div>
);
export default App;
touched, handleBlur
- formik의 props 중 touched은 name에 상태의 키 값을 지정한 요소가 클릭되었는지 아닌지 true, false로 리턴한다.
- 만약 name이 "duck"인 인풋이 클릭이 되었으면, props.touched.duck이 true가 될 것이다.
- 이를 사용하기 위해 인풋의 onBlur나 onClick에 formik의 props인 handlBlur를 넣어주면 된다!
- onBlur와 onClick의 차이점은 onBlur는 요소를 클릭한 후 다른 곳을 클릭하면 touched가 true로 변경되고, onClick은 요소를 클릭하면 그 즉시 touched가 true로 변경된다!
import React from 'react';
import { Formik } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{ onBlur: "onBlur", onClick: "onClick" }}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<input
onBlur={props.handleBlur}
value={props.values.onBlur}
onChange={props.handleChange}
name="onBlur"
/>
{props.touched.onBlur ?
<span>클릭했음</span> :
<span>아직 클릭 안함!</span>
}
<input
onClick={props.handleBlur}
value={props.values.onClick}
onChange={props.handleChange}
name="onClick"
/>
{props.touched.onClick ?
<span>클릭했음</span> :
<span>아직 클릭 안함!</span>
}
</form>
)}
</Formik>
</div>
);
export default App;
setValues()
- Formik의 setValues() prop으로 state를 변경할 수 있다!
- dynamic form을 만들 때 유용하게 쓰일 것 같다!
import React from 'react';
import { Formik } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{ name: "처음 상태" }}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<button type="submit">처음 상태 확인!</button>
<button
onClick={() => {
props.setValues({ name: "duck", height: 180 })
}}
type="submit"
>
변경된 상태 확인!
</button>
</form>
)}
</Formik>
</div>
);
export default App;
<Field />
ㅈㄴ편함- Field 컴포넌트의 디폴트는 Html의 input 태그와 같지만 onChange를 명시하지 않아도 상태가 변경이된다!
- 또한, onBlur나 onClick을 명시하지 않아도 touched의 상태를 추적할 수 있다.
- 하지만 아무것도 명시하지 않으면 onBlur가 적용 되므로 onClick을 할 때 touched가 true로 변경되길 원한다면 onClick을 명시해야 한다!
- Formik 안의 input태그와 마찬가지로 name 필드로 state의 key를 매핑할 수 있다!
- 아래 두 코드는 같은 의미이다!
<input value={props.values.name} onChange={props.handleChange} onBlur={props.handleblur} name="name"/>
<Field value={props.values.name} name="name"/>
- 예시는 아래와 같다!
import React from 'react';
import { Formik, Field } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{name: "처음 상태"}}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<Field value={props.values.name} name="name"/>
<button type="submit">변경된 상태 확인!</button>
</form>
)}
</Formik>
</div>
);
export default App;
- as prop을 사용해서 html의 input, select, textarea처럼 지정할 수 있다!
import React from 'react';
import { Formik, Field } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{name: "duck", height: 180, food: ""}}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<Field as="input" name="name"/>
<Field as="textarea" name="height"/>
<Field as="select"name="food">
<option value="hamburger">hamburger</option>
<option value="chicken">chicken</option>
</Field>
<button type="submit">변경된 상태 확인!</button>
</form>
)}
</Formik>
</div>
);
export default App;
- as prop을 select로 지정하고 name 필드를 지정하면 option에 따라 해당 name 필드의 상태가 변경된다!
import React from 'react';
import { Formik, Field } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{food: "hamburger"}}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<Field as="select"name="food">
<option value="hamburger">hamburger</option>
<option value="chicken">chicken</option>
</Field>
<button type="submit">상태 확인!</button>
</form>
)}
</Formik>
</div>
);
export default App;
<FieldArray />
- state에 array로 된 value 값이 있을 때, FieldArray 컴포넌트의 name prop에 해당 array의 key를 적어주고 하위 Field 컴포넌트의 name prop에 빽틱으로 감싸서 name={`list.${idx}.text`} 와 같이 적어주면 리스트의 인덱스에 접근해서 값을 변경할 수 있다!
import React from 'react';
import { Formik, Field, FieldArray } from 'formik';
const App = () => (
<div>
<Formik
initialValues={{
list: [
{text:" "},
{text:" "},
{text:" "}
]
}}
onSubmit={(data) => {
alert(JSON.stringify(data, null, 2));
}}
>
{(props) => (
<form onSubmit={props.handleSubmit}>
<FieldArray name="list">
{()=>(props.values.list.map((item, idx)=>{
return(
<div key={idx}>
{`input ${idx+1}:`}<Field name={`list.${idx}.text`}/>
</div>
);
}))
}
</FieldArray>
<button type="submit">상태 확인!</button>
</form>
)}
</Formik>
</div>
);
export default App;
- 만약 FieldArray 하위의 Field 컴포넌트의 name에 initialValues에 없는 key 값을 써주면 해당 key 값과 input 안의 내용이 업데이트 된다!
enableReinitialize
- 리액트의 state나 useEffect를 통해 API를 호출을 통해서 응답받은 값으로 initialValues를 설정하고자 할 때, 이처럼 formik 외부의 값에 의해서 initialValues를 설정하면 해당 외부 값들이 변해도 initialValues가 변하지 않는다!!
- 이 때 initialValues의 변함을 체크하는데는 얕은 비교가 사용된다.
- Formik은 기본적으로 enableReinitialize값이 false로 주어지기 때문에 외부 값을 initialValues에 할당하고 해당 값을 변화시켜도 initialValues가 변하게 하려면 enableReinitialize값을 true로 주면 된다!
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Formik } from "formik";
import * as Yup from "yup";
const SurveyView = (props) => {
const [survey, setSurvey] = useState({})
useEffect(() => {
props.setMenu("surveylist")
getSurvey(props.match.params.id);
}, [])
const getSurvey = async (id) => {
const res = await axios.get(`/api/survey/${id}`);
setSurvey(res.data)
}
const initialValues = {
survey: survey
}
const handleSubmit = async (value) => {
alert(JSON.stringify(value, null, 2));
}
return (
<Formik initialValues={initialValues} onSubmit={handleSubmit}
enableReinitialize={true}>
{({ values, handleChange, setValues }) => (
...
)}
</Formik>
);
}
export default SurveyView;
'Frontend > 리액트 개발 꿀팁' 카테고리의 다른 글
ESLint/Prettier 설정 (0) | 2022.06.13 |
---|---|
useState 주의사항 (0) | 2022.06.11 |
상태관리와 리덕스에 대해.. (0) | 2022.06.06 |
Yup + formik ⇨ form state 관리 validation 검증 (2) | 2021.09.09 |
map, key prop (0) | 2021.08.01 |
@덕구공 :: Duck9s'
주니어 개발자에욤
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!