들어가며
오늘은 React에서 DOM Node를 선택하는 방법에 대해 짧게 적어보려합니다. 함수 컴포넌트가 주류가 된지 꽤 오랜 시간이 지난 지금이야 당연하게도 useRef를 사용하지만, 과거 클래스 컴포넌트가 주로 사용되었을때는 이러한 훅 대신, react-dom에 포함된 findDOMNode라는 메서드를 사용하여 브라우저의 DOM Node를 선택하였습니다. 이번 포스팅에서는 해당 메서드가 어떻게 사용되었는지, 이 방식이 어떤 문제점을 가지고 있었으며 현재의 모습으로 바뀌면서 어떻게 문제를 해결했는지에 대해 알아봅니다.
findDOMNode
findDOMNode는 리액트에서 노드를 찾는 가장 원시적인 방법으로, 클래스 컴포넌트의 생명 주기 메서드 내에서 사용합니다. 찾고싶은 DOM Node를 findDOMNode 메서드의 인자로 전달합니다.
const input = findDOMNode(this);
사용 예시를 보겠습니다.
import { Component } from "react";
import { findDOMNode } from "react-dom";
export class AutoSelectInput extends Component {
componentDidMount() {
const input = findDOMNode(this);
input.select();
}
render() {
return <input defaultValue="" />;
}
}
export default function App() {
return <AutoSelectInput />;
}
컴포넌트가 마운트 된 후의 생명주기 메서드인 componentDidMount에서 findDOMNode를 사용한 모습입니다. 인자에 this를 전달하였으므로, 현재 render()에 있는 가장 최상위의 DOM Node인 <input> 태그가 선택됩니다.
console.log()를 통해 지금 찾은 노드를 확인해보면 좀 더 확실하게 알 수 있습니다.
findDOMNode의 문제점
이 방식의 가장 큰 문제점은 DOM과 선택자 사이의 연결이 명시적이지 않다는 점입니다. 두 부분이 "그 노드는 (특정한)그 곳에 있을것이다" 라는 개발자의 예측을 전제로 한 간접적인 방식으로 연결되어있기 때문입니다. 실제로 개발자의 선택자가 부정확하거나, 이후에 계층 구조가 변경되는 경우엔 의도치 않은 동작으로 이어질 수 있습니다.
render()의 input 태그를 div 태그로 감쌌더니 곧바로 오류가 발생하였습니다. 기존에는 찾은 노드가 input 태그일 것으로 예상했지만 이후의 수정으로 인하여 그 대신 div 태그가 들어왔기 때문입니다. 이처럼 간접적인 연결은 잠재적인 위험을 안고 있습니다. 그렇다면 이 문제를 어떻게 해결할 수 있을까요?
CreateRef
findDOMNode의 문제점을 해결하기 위해 등장한 것이 바로 CreateRef입니다. CreateRef는 간접적인 연결대신 해당 DOM Node에 ref를 직접 붙여서 사용합니다. 위의 코드를 CreateRef를 사용하는 방법으로 변경해보겠습니다.
import { Component, createRef } from "react";
export class AutoSelectInput extends Component {
inputRef = createRef(null);
componentDidMount() {
const input = this.inputRef.current;
input.select();
}
render() {
return (
<div>
<input ref={this.inputRef} defaultValue="" />
</div>
);
}
}
export default function App() {
return <AutoSelectInput />;
}
CreateRef를 사용하는 코드로 변경하고 나니, 중간에 어떤 코드가 들어오던 관계 없이 항상 원하는 노드를 선택할 수 있게 되었습니다. 덕분에 CreateRef는 클래스 컴포넌트에서 DOM Node를 선택하는 방법으로 널리 사용되었고, 지금 우리가 주로 사용하는 함수 컴포넌트에서는 useRef()를 통해 동일한 동작을 구현할 수 있게 되었습니다.
import { useRef, useEffect } from "react";
export function AutoSelectInput() {
const inputRef = useRef(null);
useEffect(() => {
const input = inputRef.current;
input.select();
}, []);
return (
<div>
<input ref={inputRef} defaultValue="" />
</div>
);
}
마치며
이번 포스트에 정리한 내용은 새롭게 바뀐 리액트 공식 문서에 아주 자세하게 설명되어 있습니다. 기회가 되어 해당 페이지의 번역 작업을 맡게 되었는데, 새 공식 문서에는 해당 문서에 관한 논의 내용이나 다양한 예시와 같은 기존에 리액트를 능숙하게 다루셨던 분들께도 도움이 되거나 흥미로운 내용들이 많이 있었습니다. 여유가 되신다면 바뀐 문서를 한 번 읽어보시기를 추천 드립니다.
참고자료
'이론 > Frontend' 카테고리의 다른 글
Next.js Page Router와 App Router (0) | 2023.10.08 |
---|---|
Next.js로 metadata 구성하기 (1) | 2023.09.24 |
자바스크립트에서 값 비교하기 (0) | 2023.04.23 |
검색창 영역을 위한 시멘틱 태그 <search> (0) | 2023.04.15 |
JavaScript의 모듈 시스템에 대하여 (1) | 2023.03.04 |
댓글