라이브러리 없이 제어 컴포넌트로 폼을 다룬다면?
-> React에서 제어 컴포넌트란, React를 통해 제어하게 되는 컴포넌트를 말한다.
- 제어 컴포넌트로 폼을 다루기 위해서 하나하나 state를 선언해주고, 해당 state를 다루기 위해서 또 핸들링 함수를 만들어야 하고, 에러를 위한 state, 또 검등을 위한 함수 등 모든 유효성 검증을 한다면 코드는 더더욱 길어질 것이다.
- 코드의 길이 문제뿐만이 아닌 React에서 컴포넌트 리렌더링이 발생하는 조건 중 하나는 stat값이 변했을 때이다.
모든 값이 state로 연결되어 있으며 하나의 값이 변할 때마다 여러 개의 자식 컴포넌트 들에서 무수히 많은 리렌더링이 발생한다. 이는 개발자가 예측한 렌더링이 아닌, 불필요한 렌더링으로서 불필요한 연산으로 생각할 수 있다.
- react-hook-form 설치
npm i react-hook-form
- useForm 훅 사용
- mode 옵션은 validation 전략을 설정하는데 활용한다. onSubmit, onChange, onBlur, all 등의 옵션이 있다. => 주의해야 할 점은 mode를 onChange에 놨을 때 다수의 리렌더링이 발생할 수 있어 성능에 영향을 끼칠 수 있다.
defaultValues 옵션은 form에 기본값을 제공하는 옵션이다. 주의해야할 점은 react-hook-form 을 사용할 때 기본값을 제공하지 않는 경우 input의 초기값은 undefined로 관리가 된다.
register
-
useForm을 통해서 컨트롤 할 폼 객체를 리턴받아서 destructuring한다. register 함수를 꺼내서 사용하는데, 해당 함수를 통해서 우리는 input 태그를 다룰 수 있다.
-
register 함수의 첫 번째 매개변수로는 name을 준다. 해당 필드를 다루게 될 key값으로써 반드시 들어가야 하는 값이다. 두 번째 값으론 options 객체가 들어가는데, 해당 객체에는 유효성 검사를 위한 프로퍼티들이 들어갈 수 있다.
-
유효성 검사를 통해 value만을 줄 수도 있지만 value, message로 구성된 객체를 줌으로써 해당 에러에 대한 구체적인 메세지를 제공할 수 있다.
register("name", {required: true, minLength: 10});
register("name", {required: "해당 필드는 필수입니다.", minLength: {
value: 3,
message: "3글자 이상 입력해주세요."
}
});
- 위 register 함수에 validation을 넣어줬다면, 에러에 대한 정보를 어디서 찾아야할까?
=> 에러에 대한 정보는 formState 객체의 errors에 있다. 에러가 존재하지 않다면 해당 객체는 빈 객체이며 만약 검증을 통해 에러가 발생한다면 해당 객체에 name의 객체가 생기고, 그 객체 속에 error의 타입과 메세지가 담겨져 있다.
watch
-
비제어 컴포넌트로 폼을 구현할 때 조건에 따라서 다르게 필드를 노출해야 하는 상황이 있다. 이런 상황에서 우리는 watch 함수를 활용할 수 있다. watch 함수는 폼에 입력된 값을 구독하여 실시간으로 체크할 수 있게 해주는 함수.
-
매개변수를 주지 않는다면 전체 값을 관찰할 수 있으며 매개변수를 준 다면 해당 값만 관찰할 수 있다.
-
주의할 점은 만약 관찰하려는 필드에 defaultValue를 주지 않는다면 초기 값이 undefined로 관리가 된다는 점이다.
getValues
- react-hook-form에서 값을 추적할 수 있는 방법은 두 가지가 있다. 첫 번째는 위에서 소개한 watch 함수를 활용하는 것이고, 두 번째는 getValues 함수를 활용하는 것이다. 두 방법 모두 필드에 입력된 값을 받을 수 있지만, 차이점이 있다.
watch
- 입력된 값을 추적하고 반환하며 해당 값에 따라서 리렌더링을 일으킨다.
getValues
- 값을 반환하지만 리렌더링을 발생시키지 않고 해당 값을 추적하지 않는다는 점이다.
Reset
- 해당 폼으로 creat 기능 뿐만 아니라 edit 기능까지 커버해야 한다. 사용자가 edit버큰을 클릭해 정보를 수정해야 한다면, 우리 비동기 데이터를 활용해 기존의 데이터를 폼에 뿌려줘야 한다.
- react-query 라이브러리와 함께 사용한다면 react-query에 비동기 플로우를 맡기기 때문에 reset에 관한 로직을 useQuery의 onSuccess에 넣어주었다. 이렇게 코드를 작성한 경우에는, useEffect를 줄일 수 있고 보다 확실한 타이밍에 reset을 해줌으로써 안정적인 플로우를 구현할 수있다.
handleSubmit, setError, setFocus
- 폼에서 데이터를 입력한다면 사용자는 등록 버튼을 누른다. 이때 submit 이벤트가 발생하게 되는데, 우리는 서버에 데이터를 넘기기 전에 해당 데이터에 대한 검증을 끝낼 필요가 있기때문에 form 태그의 onSubmit에 handleSubmit 이라는 함수를 넣어주고 매개변수로 우리가 정의한 onSubmit 함수를 넣어줍니다. onSubmit 함수를 정의 할 때 매개변수로 data 라는 값을 받을 수 있는데, 해당 값은 사용자가 제출 버튼을 클릭 한 후 내려오는 사용자 입장에서 최종으로 제출하는 데이터 입니다.
- onSubmit 에서는 기본 이벤트를 막아주는 event.preventDefault() 를 할 필요가 없습니다.
- onSubmit 에서 최종 데이터 검증을 하다가 어떤 에러가 체크 되었다면 setError 함수를 활용할 수 있고 setFocus 를 활용해 해당 필드에 포커스도 줄 수 있다.
react-hook-form을 활용해 똑같은 폼을 구현할 때 라이브러리에 의존성을 부여했기 때문에 직접 다뤄야하는 로직은 줄고 개발 경험을 높일 수 있다. 또한 비제어 컴포넌트를 통해 폼을 다루기 때문에 기존에 input 태그를 다루기 위해 선언했던 state가 없어지고 컴포넌트가 관리해야 하는 state 수도 적어졌다. 이로 인해서 컴포넌트의 렌더링 횟수도 최소화할 수 있었다.
React Hook Form을 사용하여 에러처리하는 방법은, 주로 폼 내부의 유효성 검사와 관련된 에러를 처리하는데 사용된다. 하지만 서버에서 반환된 에러 (로그인 실패, 사용자 존재하지 않음. 등)를 처리하기 위해서는 React Hook Form 외부의 로직이 필요하다. 여기서는 서버로부터 받은 에러 코드를 클라이언트에서 처리해야 한다.
React Hook Form을 사용할 때 'register'함수에 전달하는 이름 문자열은 폼 필드의 'name' 속성값과 일치해야 한다. 이 값은 폼 데이터를 처리할 때 해당 필드를 식별하는데 사용된다. 또한 label 의 htmlfor 속성 값도 해당 입력 필드의 id 속성 값과 일치해야 하므로 사용자가 레이블을 클릭했을 때 연결된 입력 필드가 활성화된다.
onChange이벤트 수동으로 처리할 필요 X
- React Hook form을 사용할 때는 일반적으로 각 입력 필드의 'onChange'이벤트를 수동으로 처리할 필요가 없다. 'register'함수는 입력 필드의 값 변화를 자동으로 감지하고, 해당 값을 폼의 상태에 저장한다.
따라서, setId와 setPassword 같은 상태 설정 함수와, onChange 이벤트를 처리하기 위한 핸들러 함수(handelEmailChange, handelPasswordChange)는 필요하지 않게 됩니다.
register 함수가 반환하는 객체에는 해당 필드의 onChange, onBlur , ref 등의 이벤트 핸들러와 속성이 모두 포함되어 있으며, 이들을 입력 필드에 적용한다. 이를 통해 React Hook Form은 해당 필드의 값이 변경될 때마다 자동으로 이를 감지하고, 폼의 상태를 업데이트 한다.
React Hook Form을 사용하면서도 useState를 사용하여 각 입력 필드의 상태를 따로 관리할 필요가 없어지며, 이는 코드를 훨씬 더 간결하고 관리하기 쉽게 만들어줍니다. 이 접근 방식은 폼 데이터의 유효성 검사, 에러 처리, 폼 제출 등의 기능을 구현할 때 코드의 양을 줄이고, 폼과 관련된 로직을 더 효율적으로 관리할 수 있게 해줍니다.
- 리액트 훅 폼을 사용하여 에러 처리를 하기 위해서는, 폼 내의 각 입력 필드를 'register'함수에 등록하고, 'formState'에서 제공하는 'errors'객체를 사용하여 에러 메시지를 표시한다.
이미 'useForm'에서 'errors'를 구조 분해 할당하여 받아오고 있으므로, 이를 활용하여 에러 메시지를 사용자에게 보여줄 수 있다.
리액트 훅 폼으로 커스텀 체크박스 컴포넌트를 폼에 통합하고자할 때, 몇 가지 조정이 필요한데
기본적으로 리액트 훅 폼의 'register' 함수를 사용하여 폼 요소를 등록하고 관리하지만, 커스텀 컴포넌트를 사용할 경우 'Controller'컴포넌트나 'register'의 반환 값을 직접 컴포넌트에 전달하는 방법을 사용해야 한다.