약 1년이 조금 넘는 기간 동안, 샵 관리 프로그램을 개발했다.
대부분의 데이터가 사용자의 입력을 통해 생성되는 관리 프로그램의 특성상... form과 관련된 로직을 정말로 많이 다뤘다.
온갖 요구 사항, 예외 케이스들과 마주했고, 이를 구현하기 위해 수많은 방법을 탐구했다.
그리고 내린 결론 → react에서 form 관련 로직을 다룰 때, 이만한 라이브러리는 없다.
유효성 버튼 구현
유효성 버튼이란?
→ (내 맘대로) 특정 조건이 완료되기 전까지 비활성, 특정 조건 완료 시 활성화 되는 버튼.
필수인 데이터 입력이 완료되는 순간 배경색이 바뀐다던지... 하는 버튼 정도가 되겠다.
react-hook-form에서 이를 어떻게 구현할 수 있을까?
useWatch
필수 데이터가 입력 되었을 때!를 판단하기 위해서는
이용자의 입력 행위가 발생할 때마다, 현재 form에 필수 데이터들이 입력되었는지를 체크해야 한다.
react-hook-form에서는 현재 입력된 input value들의 최신값을 watch라는 함수를 통해 받아올 수 있는데...
문제는 watch를 사용할 경우 매 입력마다 해당 페이지 전체가 리렌더링 된다는 것.
이 때 useWatch hooks를 사용해 form 관련 로직이 작성된 부모 컴포넌트와,
입력 시 리렌더링이 발생할 컴포넌트를 분리해줄 수 있다.
import React from "react";
import { useForm, useWatch } from "react-hook-form";
function Child({ control }) {
const firstName = useWatch({
control,
name: "firstName",
});
return <p>Watch: {firstName}</p>;
}
function App() {
const { register, control } = useForm({
firstName: "test"
});
return (
<form>
<input {...register("firstName")} />
<Child control={control} />
</form>
);
}
이를 이용해 우리가 원하는 유효성 버튼을 구현할 수 있겠다!
useWatch를 사용한 유효성 버튼
useWatch hooks를 통해 현재 form에 입력된 최신 상태의 데이터들을 받아올 수 있다.
그렇다면 →
유효성 검사가 필요한 field들의 name array를 받아,
useWatch를 통해 해당 field들의 input value들을 조회해,
해당 값들이 모두 입력되었는지를 자식 컴포넌트에 전달하는 컴포넌트를 만들어
유효성 버튼을 구현할 수 있을테다!!
export const FormWatch = ({
children,
control,
requiredNameArray,
}) => {
const watchFields = useWatch({control})
const isAllFormValueFilled = requiredNameArray.every(
fieldName => watchFields?.[fieldName]?.length > 0,
)
return children(isAllFormValueFilled)
}
field name이 담긴 array를 순회하면서,
form의 fieldname-value가 담긴 object인 watchFields를 통해, 최신의 입력 value들을 조회하였다.
해당 값들의 length가 모두 0보다 커야만(입력 되었을 때) true, 아니면 false를 return하여,
해당 값을 자식 컴포넌트에 전달!
이를 통해 자식 컴포넌트는, requiredNameArray로 넘긴 field name에 해당되는 값들이 모두 입력되었는지를 반환받게 된다.
→ 이를 기반으로 UI를 다르게 보여주면 될 테다!
<FormWatchEmptyCheck
control={control}
requiredNameArray={[
// 이름, 전화번호 input이 필수
'name',
'phone_number',
]}
>
{isAllFormValueFilled => (
<FormButton
disabled={!isAllFormValueFilled}
deactive={!isAllFormValueFilled}
>
완료
</FormButton>
)}
</FormWatchEmptyCheck>
유효성 버튼이 필요한 곳에서 사용한 모습!
필수 값들이 모두 입력된 경우에만 disabled와 deactive가 false이도록 작성하면 되겠다.
TODOs
1. 일반적으로는 위와 같이... 필수값을 입력하기만 하면 유효성 버튼의 UI가 바뀔테다.
해당 값의 유효성 검사(rules에 해당, maxLength, 정규식 등)는 react-hook-form의 handleSumit이 실행될 때 수행되는데...
유효성 검사의 조건이 필수값 입력 여부 뿐만 아니라 rules에 해당되는 로직까지 포함된다면?
거기다 특정 field는 필수 여부를, 특정 field는 rules 여부를 체크해야 한다면?
위 컴포넌트만으로는 이를 처리할 수 없을테다.
→ react-hook-form의 errors 객체를 이용해, watch 컴포넌트가 리렌더링 될 때마다 각 field name에 해당하는 error가 존재하는지 반환하는 형태로 구현할 수 있겠다..!
2. requiredNameArray을 n만큼 순회
위 방식은... 모든 input 입력이 발생할 때마다 FormWatch 컴포넌트가 리렌더링 된다.
이 때 각 리렌더링 마다 requiredNameArray를 전체 순회하는데...
이것이 정말 최선의 방법일까? 하는 의문은 계속해서 남는 중.
하지만 유효성 버튼 자체가 모든 입력 때마다 유효 여부를 체크할 수 밖에 없지 않나???
'source-code > React' 카테고리의 다른 글
react-query와 error 전파 handling (0) | 2023.08.16 |
---|---|
Suspense를 통한 Render-as-you-fetch (0) | 2023.08.16 |
react에서 long press 구현하기 (0) | 2023.08.16 |
Inversion of Control (0) | 2023.08.16 |
Reconciliation (재조정) (0) | 2023.08.16 |