2021. 9. 12. 17:15ㆍIT/WEB
useRef는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다.
브라우저에서 js의 존재이유는 DOM의 조작입니다.
어떤 이벤트를 받아서 처리하고, 있는 객체를 움직이거나 변화하는 등 모든 DOM의 조작은 js를 사용함으로써 정적 정체성을 탈피합니다.
물론 CSS를 통해서도 움직임을 줄 수야 있지만 우리가 생각하는 다이나믹한 이벤트 핸들링은 복잡하거나 불가합니다.
문제는 리액트에서 DOM 요소의 조작입니다. 리액트는 렌더링을 하며 virtual DOM이라 불리는 가상 DOM을 먼저 만들고, 그것을 실제 생성된 DOM과 비교하여 차이가 있는 부분만을 리렌더링하는 방식을 통해 효율성을 담보합니다. 이러한 설계 방식의 DOM의 재사용성을 극대화 한다는 React의 철학을 보여줍니다.
자, 먼저 우리가 평소 DOM을 어떻게 조작하는 지를 살펴봅시다.
가장 대표적인 예는 바로 스크롤 바와 같은 다양한 ref예시 중 focus()를 예로 들어 보겠습니다.
document.getElementbyClassName("#a").focus();
위와 같은 코드가 있을 때, 이를 리액트의 functional component에서 평소처럼 직접 DOM에 접근하여 포커스를 줄 경우 별 문제 없이 작동할 것처럼 보입니다.
그러나 재사용성이라는 React의 환상적인 효율은 이 작동에 실제로 문제를 발생시킵니다.
요컨데 id라 함은 class와 달리 DOM의 개별 노드에 고유성을 부여해주기 위해 사용됩니다. 따라서 같은 id는 두 개 이상 존재하지 않습니다. 그런데 이 컴포넌트에 속한 DOM 노드에 id가 부여되면 컴포넌트가 재사용 될 때마다 해당 id를 가진 DOM 노드가 복제되고 이 때 id는 그 고유성을 잃게 됩니다.
따라서 이 때 useRef를 사용하여 반환된 ref 객체를 요소에 할당하면 해당 컴포넌트의 생애주기 동안 ref가 정의된 컴포넌트의 context 안에서 유일성을 보장하는 역할을 수행하게 되고, 이 때 반환된 객체의 .current 프로퍼티를 통해 DOM의 직접 조작이 가능해집니다. 다음과 같이 말이죠.
이렇게 되면 React 공식 document에서 언급하고 있는 것처럼 .current 프로퍼리에 변경 가능한 값을 담도록 해주는 하나의 예쁜 "상자"로 탄생하게 됩니다.
어? 이는 언뜻 state와 의미가 일면 상충하는 듯 보입니다. 상태란, 공식적으로 컴포넌트의 변경 가능한 데이터 저장소를 의미합니다. 그렇다면 분명 ref와 state는 유의미한 차이를 가지고 있어야 합니다. 이 때 이 둘을 분리하는 주요한 특징은 바로 렌더링에 관여하는가. 또 값의 유효한 접근 범위는 어디까지인가를 꼽을 수 있을 것 같습니다.
먼저 앞서 말했던 것과 같이 state는 component의 props로 전달하는 등의 방법을 통해 context를 외부에서 접근이 가능하지만 useRef를 통해 생성된 ref의 조작은 정의된 컴포넌트의 내부에서만 가능합니다.
이러한 특징보다 중요한 것은 useRef는 내용이 변경될 때 그것을 알려주지 않는다는 점 입니다. .current 프로퍼티의 변경은 어디에서도 관찰 가능하지 않고, 따라서 렌더링을 발생시키지 않습니다. 이에 반해 state는 useState를 호출하는 순간 비동기적으로 state를 업데이트함에 따라 컴포넌트를 리렌더링합니다. 이러한 맥락에서 useRef와 state는 차이를 갖게 됩니다.
이러한 한계에도 불구하고 종종 DOM 노드에 ref를 attach 혹은 detach하는 과정에서 단순 할당 이상의 과정을 수행해야하는 경우가 있습니다. 이때 우리는 콜백 ref를 사용하게 됩니다. 콜백 ref에 관해서는 다음 포스팅에서 다루어 보겠습니다.
*부족한 부분, 잘못된 부분은 댓글로 알려주시면 소중히 공부하겠습니다.