티스토리 뷰
리액트에서 <input type='text' />를 제어하는 방법은 보통 아래와 같다.
import React, { ChangeEvent, useState } from 'react';
const ControlledInput = () => {
const [text, setText] = useState('');
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
setText(e.target.value);
};
return (
<div>
<input type="text" value={text} onChange={handleChange} />
</div>
);
};
export default ControlledInput;
사용자의 텍스트 입력 시 상태변화를 리액트에서 자신의 state로 관리하고 업데이트한다.
당연하다시피 사용하고 있는 이 방식의 Input은 리액트에서 상태를 관리하는 '제어 컴포넌트'이다.
그러면 '비제어 컴포넌트'는 무엇일까
import React, { FormEvent, useRef } from 'react';
const UnControlledInput = () => {
const unControlledRef = useRef<HTMLInputElement>(null);
const handleSubmit = (e: FormEvent) => {
e.preventDefault();
if (unControlledRef.current) console.log(unControlledRef.current.value);
};
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={unControlledRef} />
</form>
);
};
export default UnControlledInput;
비제어 컴포넌트는 바닐라자바스크립트에서와 같이 현재상태를 DOM프로퍼티로 관리한다.
즉 리액트가 관리하는 state와 동기화되지 않는 것이다.
그러면 뭐가 좋은 거지?
이에 대한 답은 상황에 따라 다르다.
비제어 컴포넌트에서 안 되는 것들만 설명하자면
즉각적인 필드의 유효성검사가 불가하다.
조건부로 제출버튼을 비활성화하는 것이 불가하다.
인풋값의 형태를 즉시 재조정할 수 없다.
동적입력이 불가하다. 그 이유는 아래와 같다.
제어 컴포넌트의 경우에는 매번 상태가 변할 때마다(자음, 모음이 하나씩 변할 때마다) 전부 상태를 동기화하면서
state변경에 따른 리랜더링이 발생한다.
반면에 비제어컴포넌트는 상태를 DOM프로퍼티로 관리하므로 리액트는 이 state에 대해 전혀 모르는 상태가 된다.
비제어 컴포넌트는 상태의 변경을 추적할 수 없으므로 자연스럽게 위 표와 같은 특징이 나타날 수밖에 없게 된다.
그에 따라 state변경에 따른 리랜더링이 발생하지 않는다.
만약 즉각적인 필드의 유효성검사, 조건부로 제출버튼을 비활성화하는 것, 인풋값의 형태를 즉시 재조정하는 것, 동적입력이
필요 없다면 비제어컴포넌트를 사용함으로써 불필요한 리랜더링을 감소시킬 수 있다.
위 영상은 제어컴포넌트인 input의 state가 바뀔 때마다 하위컴포넌트인 gridTable도 리랜더링 되는 모습이다.
gridTable의 리랜더링을 방지하기 위해 memo(GridTable)을 해주고 props에 전달되는 함수에 메모이제이션을 해줬다.
GridTable에 메모이제이션으로 리랜더링은 막았지만 그것을 감싸는 Container나 다른 요소의 리랜더링은 방지할 수 없었다.
만약 input을 비제어 컴포넌트로 사용한다면 어떻게 될까
GridTable뿐만 아니라 모든 컴포넌트에서 리랜더링이 발생하지 않는다. input의 상태가 리액트 state가 아니기 때문이다.
검색용 Input에 즉각적인 필드의 유효성검사, 조건부로 제출버튼을 비활성화하는 것, 인풋값의 형태를 즉시 재조정하는 것, 동적입력이 필요 없다면 일부 사용해도 괜찮을 것 같다.
참, react-hook-form 라이브러리가 바로 비제어 컴포넌트를 활용해서 랜더링최적화를 한다고 한다.
react-hook-form이 단순히 폼을 통제하는 로직을 추상화해 주는 것이라고 생각해서 굳이 쓰지는 않았는데
비제어컴포넌트를 통해 리랜더링을 최적화하면서도 즉각적인 필드의 유효성검사라든지, 조건부 비활성화 같은 것을 지원하므로
복잡한 폼을 다룰 때 적용을 고려해 봐야겠다.
'React' 카테고리의 다른 글
React에서 svg를 다루는 방법 (1) | 2023.11.09 |
---|---|
useReducer, Context 로 복잡한 상태(state) 개선하기 (5) | 2023.11.08 |
react lazy import 이후 발생한 loading chunk failed 에러 해결 (0) | 2023.05.26 |
페이지 로딩 성능개선 gzip, lazy loading, code splitting (3) | 2023.05.16 |
처음 고민해본 프론트엔드 아키텍처와 디자인패턴 (0) | 2023.04.16 |