웹 애플리케이션의 상태는 화면에 변화를 일으키기 때문에 다방면으로 고려해야 한다.
대표적으로 인풋이 많은 폼에서 리렌더링으로 인한 성능 저하가 발생하기 쉽다.
이때 고려할 수 있는 제어 컴포넌트(state)와 비제어 컴포넌트(ref)를 구분하여 다루는 것이 좋다.
컴포넌트 단위 개발
현대 웹은 컴포넌트 단위로 개발되고 있다.
복잡한 사용자 인터페이스(User Interface), 개인화 된 경험(User Experience)을 기대하는 사용자, 즉 UI에 보다 많은 로직이 필요해지면서 UI를 모듈식으로 세분화하여 문제를 해결했다. 컴포넌트를 분리하고 재구성하여 다른 UI를 구축할 수 있게 되었다.
컴포넌트 단위로 개발하다보면 스스로 짠 코드에 엉켜 넘어질 수 있다.
컴포넌트 내부에 가진 정보들이 먼 곳에 떨어진 다른 컴포넌트로 전달되야 하거나, 앱 전체에서 접근 가능하도록 관리하기도 해야 한다.
성능 측면에서 뿐만 아니라 구조적으로도 이를 잘 고려해야 한다.
문제 해결 방법을 패턴화한 일종의 모범 답안이 있다. (MVC, Observer Pattern, Flux, Container-Presenter)
제어 컴포넌트
컴포넌트의 정보가 지역 state 대신 prop에 의해 만들어지는 경우, 부모 컴포넌트가 동작을 완전히 지정할 수 있어 컴포넌트가 "제어된다"고 말한다.
값은 state로 존재해야 하고, 어딘가에 저장되어 있어야 한다. 새로운 속성이 추가될 때마다 이벤트 핸들러가 호출된다. (흔히 비제어 컴포넌트보다 더 리액트스럽다고 얘기한다.)
- 빈 문자열 ""로 시작한다.
- a를 입력하면 handleNameChange가 a를 가져와 setState를 호출한다. 그런 다음 입력이 다시 렌더링 되어 a의 값을 갖는다.
- b를 입력하면 handleNameChange가 ab를 가져와 이를 state로 설정한다. 입력이 다시 한 번 렌더링 되어 value="ab"가 된다.
값 변경을 폼 컴포넌트에 '푸시(push)'하므로 폼 컴포넌트는 명시적으로 요청할 필요 없이 항상 입력의 현재 값을 갖는다.
즉, 데이터(state)와 UI(인풋)이 항상 동기화 되고 이를 위해 값이 바뀔 때마다 리렌더링이 발생한다.
리렌더링 조건
- 컴포넌트의 state가 변경되었을 때
- 컴포넌트가 상속받은 props가 변경되었을 때
- 부모 컴포넌트가 리렌더링이 된 경우 자식 컴포넌트는 모두 리렌더링
비제어 컴포넌트
지역 state를 갖는 컴포넌트. 해당 컴포넌트 부모에서 지역 state에 영향을 줄 수 없기 때문에 "제어되지 않는"다고 한다.
부모 컴포넌트에서 사용하기 더 쉽지만 여러 컴포넌트를 함께 조정하려고 할 때 덜 유연하다.
전통적인 HTML 폼 인풋과 유사하다.
내가 입력한 내용을 기억하고 ref를 사용해 값을 가져올 수 있다. 즉, 필요할 때 필드에서 값을 '가져와야' 한다.
사용 사례
입력한 값을 실시간으로 반영하여 미리보기 화면을 구현할 때 state를 사용해 폼을 구성했다.
반면, submit 이벤트가 발생할 때 값을 업데이트 해도 되는 경우(일반적인 폼),
그리고 DOM에 직접 접근하여 값을 확인하고 싶은 경우(ex. 드롭다운) ref를 사용했다.
진행중인 프로젝트에서 커스텀 훅 useForm을 만들어서 사용하고 있는데 해당 훅은 ref로 상태를 관리한다.
const dropdownMenuRef = useRef<HTMLDivElement>(null);
/** 드롭다운 내부 영역의 참조값(ref)은 드롭다운 외부 영역을 클릭하면 초기화(false)됩니다. */
useEffect(() => {
const clickDropdownOutside = (event: MouseEvent) => {
if (dropdownMenuRef.current && !dropdownMenuRef.current.contains(event.target as Node)) {
closeDropdownMenu();
}
};
document.addEventListener('mousedown', clickDropdownOutside);
return () => {
document.removeEventListener('mousedown', clickDropdownOutside);
};
}, []);
'기술 스택' 카테고리의 다른 글
Vite로 React 프로젝트 시작하기 (ESLint, Prettier, tsconfigPaths) (0) | 2024.01.05 |
---|