최근 리액트를 이용해 간단한 사이드 프로젝트를 진행하고 있습니다.
프론트엔드 개발자로써 사실 리액트보다 vue를 쓰는 기간이 더 많아서, 아직 react에 적응하는 기간인데
사용하면서 가장 곤란했던 부분이 있습니다.
바로 vue는 양방향의 데이터바인딩을 지원하지만, react는 오직 단방향만 지원한다는 점입니다.
오늘은 이 부분을 단적으로 보여주는 react의 useImperativeHandle에 대해서 적어보도록 하겠습니다.
useImperativeHandle
useImperativeHandle은 ref를 통해 부모 컴포넌트에 노출할 인스턴스 값을 사용자 커스텀할 수 있는 기능입니다. 이를 통해 부모 컴포넌트는 자식 컴포넌트에 원하는 인스턴스를 호출할 수있습니다. 주로 fowardRef와 같이 사용합니다.
const CustomComponent = forwardRef((props, ref) => {
//...
useImperativeHandle(ref, () => ({
handleCustomLog: (type, value) => {
console.log('custom log')
}
}));
// ...
});
const ParentComponent = () => {
const customRef = useRef(null);
const handleLog = () => {
if (customRef.current) {
customRef.current.handleCustomLog();
}
};
return (
<CustomComponent
ref={customRef}
/..
/>
);
};
react 19 버전을 기준으로 forwardRef는 삭제 됐으니, ref로 사용하셔도 무방합니다.
어쨌든 코드를 작성해보니 vue의 defineExpose()와 유사합니다. vue에서는 defineExpose()를 통한 양방향의 데이터바인딩을 권장하고 있지만 , react에서는 권장하지 않는 방식입니다.
주요 이유는 아래와 같습니다.
- 명령형(Imperative) 코드를 조장함
- React는 "무엇을(what)" 렌더링할지 선언하는 방식을 지향하는데, useImperativeHandle은 "어떻게(how)" 동작할지 명령하는 방식입니다.
- 부모가 자식의 메서드를 직접 호출하는 것은 명령형 패턴입니다.
- 컴포넌트 캡슐화를 깨뜨림
- 자식 컴포넌트의 내부 구현을 부모에게 노출하게 되어, 컴포넌트의 독립성이 약화됩니다.
- 자식의 내부 구조를 변경하면 부모 코드도 함께 수정해야 할 수 있습니다.
- 데이터 흐름을 추적하기 어려움
- props를 통한 단방향 흐름이 아니라 ref를 통한 직접 제어이기 때문에, 코드를 읽을 때 데이터 흐름을 파악하기 힘듭니다.
- 테스트와 유지보수가 어려움
- ref를 통한 직접 조작은 테스트 코드 작성이 복잡해지고, 디버깅도 어렵습니다.
그럼에도 사용해야 한다면 사용하는 게 맞습니다. 저는 dom 제어를 위해서 사용할 것 같습니다.
'react' 카테고리의 다른 글
| react로 그림판을 만든 뒤 후기 [0] (0) | 2025.12.10 |
|---|---|
| [react] setState에 관하여. (0) | 2019.03.24 |
| 리액트 router의 activeClassname에 관한 팁. (0) | 2019.02.25 |