[React] react-hook-form 배열 다루기 (useFieldArray)
react-hook-form에서 배열을 다룰 때는 useFieldArray hook을 사용하면 된다. 그러나 이 hook을 사용할 땐 주의할 점이 있는데 우선 안되는 코드를 살펴보고 잘 되는 코드를 확인해보자. (참고 : 이전 게시글에서 소개한 초기값, 출력과 같은 부분 설명은 제외함.)
수정 전 코드
import { Controller, useFieldArray, useForm } from "react-hook-form";
// # 초기값
const initValue = {
numbers: []
};
const Basic = () => {
const { control, handleSubmit } = useForm({
mode: "onSubmit",
defaultValues: initValue
});
// #1 useFieldArray 값
const { fields, append } = useFieldArray({
control: control,
name: "numbers"
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* #2 fields.map 그리기 */}
{fields.map((item, index) => {
return (
<div key={index}>
<Controller
control={control}
// #3 name
name={`numbers[${index}]`}
defaultValue=""
render={({ field }) => (
<input margin="dense" variant="outlined" {...field} />
)}
/>
</div>
);
})}
<div>
<button
onClick={() => {
// #4 배열 요소 추가하기
append("");
}}
>
추가
</button>
{/* #5 값 확인하기 */}
<button onClick={() => console.log("# fields", fields)}>
값 확인하기
</button>
</div>
<input type="submit" />
</form>
);
};
export default Basic;
#1 useFieldArray 값
useFieldArray의 값은 fields이다. 즉 배열 값이 fields로 사용이 된다. 그리고 append 라는 함수가 있는데, 배열에 원소를 추가할 때 사용이 된다. 추가적인 함수로는 prepend, remove, swap, move, insert가 있다. (홈페이지 참고 : 이동하기)
#2 fields로 컴포넌트 그리기
fields가 배열 값이니 map을 통해 배열을 반복하면서 안의 원소 값으로 컴포넌트를 그리는 코드이다.
#3 name
name은 이전 게시글에서 값에 접근할 수 있도록 적어주면 된다고 했다. 배열 원소에 접근하는 방법으로 name을 적어주었다.
#4 배열 원소 추가하가
useFieldArray에서 원소를 추가하는 방법은 arr.push(원소)가 아닌 append(원소)이다.
#5 값 확인하기
초기 값이 [] 빈 배열이니 append를 하게 되면 [""]로 될 것 같다. 아래 결과 값을 확인해보자.
그러나 우리의 예상과 다르게 너무 이상한 값이 들어가있다. 왜 그럴까? 필자도 정확한 이유는 모르겠지만, 공식 홈페이지를 참고해보면 사용법이 잘못되었음을 알 수 있다.
설명을 보면 flat field array를 지원하지 않는다고 되어 있는데, 아마 flat field array가 그냥 숫자 배열, 문자열 배열 등을 뜻하는 것 같다. 그럼 어떻게하면 사용할 수 있을까? 아래 수정 후 코드를 확인해보자.
수정 후 코드
import { Controller, useFieldArray, useForm } from "react-hook-form";
// # 초기값
const initValue = {
numbers: []
};
const Basic = () => {
const { control, handleSubmit } = useForm({
mode: "onSubmit",
defaultValues: initValue
});
// #1 useFieldArray 값
const { fields, append } = useFieldArray({
control: control,
name: "numbers"
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
{/* #2 fields.map 그리기 */}
{fields.map((item, index) => {
return (
<div key={index}>
<Controller
control={control}
// #3 name
name={`numbers[${index}].value`}
defaultValue=""
render={({ field }) => (
<input margin="dense" variant="outlined" {...field} />
)}
/>
</div>
);
})}
<div>
<button
onClick={() => {
// #4 배열 요소 추가하기
append({ value: "" });
}}
>
추가
</button>
{/* #5 값 확인하기 */}
<button onClick={() => console.log("# fields", fields)}>
값 확인하기
</button>
</div>
<input type="submit" />
</form>
);
};
export default Basic;
사실 크게 변경된 곳은 없다. #3, #4만 변경해주었다. 왜 위와 같은 코드로 변경을 하면 잘 동작할까? 이유는 간단하다. flat field가 안되니 object로 변경해준 것이다. 즉 기존에는 const numbers = [1, 2, 3]이 었다면 지금은 const numbers = [{ value : 1 }, { value : 2 }, { value : 3 }] 인 것이다.
그러나 위와 같은 경우, 우리가 원하는 실제 numbers가 [1,2,3] 인 경우 const result = numbers.map(item => item.value); 로 빼내야 하는데 이게 맞는 방법인가 싶다. 결론적으로 const numbers = [1,2,3,4] 와 같은 경우는 useFieldArray로는 사용하지 못 하는건지, 방법을 모르는 건지 궁금하다. 혹시 아시는 분 있으면 댓글로 가르쳐주시면 감사하겠습니다.
마지막
해당 내용은 틀릴 수도 있다는 것을 감안하여 봐주세요. 틀린 내용 및 오탈자 수정 요청 환영입니다.
'기타 (+ Legacy) > Legacy' 카테고리의 다른 글
[Legacy][React] react-hook-form - 4 (useFormContext) (0) | 2021.10.16 |
---|---|
[Legacy][React] react-hook-form 배열 다루기 - 3 (0) | 2021.10.15 |
[Legacy][React] react-hook-form 소개 및 사용법 - 1 (0) | 2021.10.13 |
[React] 특정 컴포넌트 프린트 하기 (0) | 2021.10.12 |
[Legacy][React] useRef, ref (0) | 2021.04.13 |