Tech
React Hook Form의 isDirty와 dirtyFields를 알아보자
2022. 06. 07
그래서 사용법이나 함수들에 대한 설명을 하지 않습니다.
제가 개발하고 있는 화해 비즈니스 센터에서는 Form을 관리하기 위해서 React Hook Form(이하 RHF)을 이용하고 있습니다. RHF을 이용하면 Form의 입력값 검증이나 필드 상태 확인 등을 편리하게 할 수 있습니다. React Hook Form isDirty
이번 글에서는 RHF의 필드 상태 확인에서 isDirty와 dirtyFields에 집중해서 이야기해보려 합니다.
웹에서 Form을 다루다 보면 Form의 모든 필드 중에 하나라도 사용자 입력이 있었는지 알고 싶을 때가 있습니다. 예를 들면, 사용자로부터 설문을 받는 Form이 있을 때 사용자가 한 문항이라도 입력한 게 있는 상태에서 페이지를 이탈하려고 하면 정말 이탈할 것인지 확인창을 띄우고 싶은 경우가 그렇습니다.
이런 경우에 React Hook Form을 사용한다면 formState
안의 isDirty
또는 dirtyFields
속성을 활용할 수 있습니다. 각각에 대한 공식 문서 설명은 아래와 같습니다.
- isDirty: Set to
true
after the user modifies any of the inputs. Make sure to provide all inputs’ defaultValues at the useForm, so hook form can have a single source of truth to compare whether the form is dirty. - dirtyFields: An object with the user-modified fields. Make sure to provide all inputs’ defaultValues via useForm, so the library can compare against the
defaultValues
.
위의 설명을 보고 이렇게 생각했습니다. ‘아! isDirty
는 어떤 필드든 사용자 입력이 있었는지 확인할 때 쓰면 되겠고, dirtyFields
는 어떤 필드에 사용자 입력이 있었는지 콕 집어서 알아야 할 때 사용하면 되겠구나!’
이번에 만들어야 하는 기능에서는 어떤 필드든 사용자 입력이 있었는지만 확인하면 되어서 처음에는 isDirty
를 사용했습니다. 그런데, isDirty
가 true가 된 이후에 모든 값이 defaultValue로 돌아가더라도 false로 돌아오지 않는 현상이 발생해서 난항을 겪었습니다. 결국, 해당 기능은 dirtyFields
가 비었는지 확인하는 방식으로 구현하게 되었습니다.
개인적으로 위의 현상이 정말 이해되지 않았습니다. 문서의 설명만 봐서는 isDirty
가 true가 되었다가 defaultValue와 값이 같으면 false로 바뀌어야 하는 게 맞는데 결과적으로는 그렇지 않았고, isDirty
는 dirtyFields
가 비었는지를 더 편하게 확인하라고 가공해준 것인 줄 알았는데 isDirty
와 dirtyFields
가 싱크가 맞지 않았습니다.
그래서 isDirty
와 dirtyFields
가 어떻게 다른지, 어떻게 다뤄지는지 알아보게 되었습니다.
RHF의 Github Issues에는 아래와 같은 제목으로 Issue가 올라온 게 있었습니다.
- #7970 issue: Form
isDirty
doesn’t always matchdirtyFields
- #7845 issue: isDirty and dirtyFields are not in sync
isDirty
와 dirtyFields
가 싱크가 맞지 않는 것에 대해서 저 말고도 의문을 가지는 사람들이 있었네요. 이런 문의에 대한 RHF 프로젝트 member들의 답변을 살펴보면서 제가 정리하고 이해한 내용은 아래와 같습니다.
isDirty
는 form level에서 defaultValues 값과 현재 form의 값을 깊은 비교를 해서 나오는 상태 값이다.
dirtyFields
는 각 input의 상태값이다(사용자로부터 값의 변경이 있었는지를 나타내는 상태 값). input의 값에 대한 상태 값이 아니다.
위의 정리는 RHF의 코드를 보면 더 이해하기 쉽습니다.
RHF에서 필드의 값을 바꾸는 방법은 2가지가 있습니다. 한 가지는 input의 onChange 이벤트에 RHF의 핸들러를 등록하는 방법(register
함수 사용)이고 다른 한 가지는 RHF의 setValue
함수를 이용해서 수동으로 넣어주는 방법입니다.
위의 두 가지 방법 모두 필드 값이 변경될 때 내부적으로 updateTouchAndDirty
함수를 실행해서 isDirty
와 dirtyFields
를 결정합니다. 단, setValue는 option으로 shouldTouch
또는 shouldDirty
를 true로 설정하지 않으면 updateTouchAndDirty
함수가 실행되지 않습니다.
이 함수가 실행이 되면 isDirty
와 dirtyFields
에 대해서 각각 아래와 같은 로직을 수행하게 됩니다.
isDirty
는 무조건 value의 깊은 비교를 통해서 상태 값이 결정됩니다.
dirtyFields
도 개별 필드 value의 깊은 비교를 통해서 최종적인 상태 값이 결정되기는 합니다. 그러나 dirtyFields
는 isBlurEvent
와 shouldDirty
라는 option에 의해서 dirtyFields
에 필드를 넣을지 말지 결정할 수 있습니다. 이것이 dirtyFields
가 값에 대한 상태 값이 아니라 input의 상태값이라고 말하는 이유입니다. 값에 대한 상태 값이었다면 default값과 현재 값이 같은지를 나타내겠지만, 값이 변경되더라도 옵션으로 상태 값을 변경하지 않고 이전 상태값을 유지할 수 있기 때문에 input의 상태를 나타내는 속성일 뿐인 것입니다.
isDirty
와 dirtyFields
를 혼동하고 있던 시기에 RFH의 공식문서에서 dirtyFields
에 아래의 설명문이 추가되었습니다.
Dirty fields will not represent as
isDirty
formState, because dirty fields are marked field dirty at field level rather the entire form. If you want to determine the entire form state useisDirty
instead.
사실 위의 문장을 보고도 isDirty
와 dirtyFields
가 어떻게 다른지 바로 알아차리지는 못 했습니다.
혹시 비슷한 문제로 어려움을 겪고 계시는 분들에게 이 글이 도움이 되기를 바랍니다.
여기까지 정리를 하고 나면 한 가지 의아한 점이 있을 겁니다. 제 경험에서는 현재 Form의 값이 defaultValue와 같아지더라도 isDirty
가 false가 되지 않는다고 위에서 말씀드렸습니다. 이 현상의 이유는, setValue
함수를 써서 필드의 값을 변경하면서 shouldDirty
option을 true로 설정하지 않았기 때문입니다. 위에서 언급했듯이 setValue
함수를 사용할 때 shouldDirty
option을 true로 설정하지 않으면 updateTouchAndDirty
함수가 실행되지 않고 그러면 isDirty
를 다시 계산하지 않습니다.
지금까지 isDirty
와 dirtyFields
와 관련된 저의 경험과 제가 알아본 정보들을 소개해드렸는데요. isDirty
와 dirtyFields
는 Form과 관련된 기능을 편리하게 만들 수 있는 유용한 기능이지만, 이 상태 값들이 어떻게 계산되는지, 어떤 속성이 영향을 주는지 제대로 알고 사용해야 생각대로 동작합니다. 저는 꽤나 헤맸지만 이 글을 읽으신 분들은 조금만 헤매고 잘 풀리길 바랍니다~ 🙂
이 콘텐츠가 마음에 드셨다면 화해 프론트엔드 플랫폼의 다른 글도 확인해보세요!
✅ React Query와 함께하는 API 에러 처리 설계하기
✅ <htmI> | 프론트엔드 플랫폼 , “성장도 공유도 멈추지 않는다”
React Hook Form isDirty