ref 는 current 어트리뷰트 하나를 가진 객체이다.
{current: null}
컴포넌트가 mount될 때 react는 current 프로퍼티에 DOM엘리먼트를 대입하고, 컴포넌트 mount가 해제될 때 current 프로퍼티를 다시 null로 돌려놓게 된다.
즉, ref가 엘리먼트에 전달되었을 때 노드를 향한 참조는 ref의 current 어트리뷰트에 담기게 된다.
주로 ref를 사용할 때는 비제어 컴포넌트를 제어할 때이다. 비제어 컴포넌트란 react 가 제어하지 않는 컴포넌트를 말한다. 즉, react가 제공하는 재조정과 같은 feature들을 이용하지 않는 컴포넌트이다.
ref는 주로 dom element에 접근하여 컴포넌트 전체 렌더링과 관계 없는 작업을 할 때 유용하게 사용한다. 즉, 변경은 관리해야하지만 리렌더링은 시키지 않아도 되는 값을 다룰 때 사용한다.
useRef() 로 생성한 ref.current 에 HTMLElement 뿐만 아니라 숫자, 문자열, 배열 등의 값을 할당 할 수 있다.
ref.current 값은 컴포넌트가 mount되기 이전에는 null의 값을 가지며, mount 가 되기 시작해서 componentDidMount 또는 componentDidUpdate 가 되기 전에 DOM 요소가 ref 에 담기게 된다.
이에 따라 querySelect로 DOM 요소를 불러오면 라이프사이클에 따라 DOM 요소를 가져오지 못할 수 있으므로 ref 를 사용해주는게 안전하다.
ref의 값을 업데이트 하는 것은 side Effect이므로, 컴포넌트의 렌더링을 방해해선 안된다. 그러므로 반드시 컴포넌트가 마운트 되고 난 직후 (useEffect) 내에서 쓰거나 이벤트가 발생할 때 실행 (event handler) 안에서만 업데이트가 발생하도록 코드를 작성하여야 한다.
컴포넌트가 mount된 상태에서는 렌더링이 추가적으로 발생하지 않는다.
input에 ref 를 걸어주면 입력할 때마다 리렌더링이 일어나지 않기 때문에 최적화가 될 수도 있다.
class 컴포넌트에서는 createRef 를 사용하며, 함수 컴포넌트에서는 useRef 라는 hook을 사용하여 react 엘리먼트에 ref 를 부착하여 사용하게 된다.
함수형 컴포넌트에서 createRef 보다 useRef 를 사용해야하는 이유=>
createRef는 컴포넌트가 재렌더링 될 때마다 새로 생성, useRef 는 state를 유지한다.
ref가 set되고 unset될 때를 더 잘 컨트롤 할 수 있게 하는 함수를 전달한다.
DOM Node에 ref가 attact 되거나 detach 될 때 어떤 코드를 실행하고 싶을 때 사용한다. ref는 렌더링될 때를 감지하거나 변경하지 않으므로 callback Ref를 사용하여 대신 감지 해주는 것이다.
callback ref 방식을 몰랐을 때 특정 DOM Node의 높이를 구하기 위해 useState, useRef, useEffect 3개의 hook을 이용하여 구현해야 했는데 callback ref를 사용하고 구현이 쉬워질 수 있었다.
react 컴포넌트는 기본적으로 ref props를 가지고 있는데, 그것과 겹치게 된다. 따라서 ref는 일반적인 props로 전달되지 않는다.
따라서 함수형 컴포넌트에서 부모 컴포넌트에서 자식 컴포넌트로 ref를 넘겨줄 때는 forwardRef 를 사용하여야 한다.
처음 createRef()를 부른 곳에서 자식 dom의 node에 직접적으로 접근할 수 있다.
<참고자료>