리액트의 Ref는 references의 줄임말로, 리액트 컴포넌트에서 DOM 노드를 직접적으로 참조하고 상호작용할 수 있게 해준다.
예를 들어 Input 박스에 포커스를 맞추는 기능 같은 것이 가장 대표적인 활용 방법이다.
특히 Ref가 컴포넌트 내에서 특정 정보를 참조해야할 때 사용되며, 동시에 해당 정보가 리렌더링을 일으키지 않도록 할 때 유용하다.
리액트에서는 ref를 두 가지 방법으로 만들 수 있는데, 바로 createRef 메서드 또는 useRef 훅이다.
useRef 훅은 리액트 라이브러리가 함수형으로 재편되었을 때 나온 훅으로, 함수형 컴포넌트에서 더욱 효과적으로 사용할 수 있다.
위 코드에서는 useRef() 훅을 사용하여 버튼 엘리먼트에 대한 참조를 만들고 buttonRef라는 이름으로 선언한다.
이 참조를 활용하면 buttonRef.current를 통해 현재 buttonRef의 값을 얻을 수 있다.
refs를 사용하면 값들을 저장하고 업데이트할 수 있으며, 렌더링을 효과적으로 관리할 수 있다.
createRef 메서드를 사용하여 Ref를 만드는 방법은 훅이 나오기 전에 리액트가 클래스 기반으로 작성되었을 당시의 방법이다.
위 코드에서는 React.createRef()를 통해 buttonRef라는 이름의 'refs'를 생성하고, 해당 참조를 버튼 엘리먼트에 할당한다.
createRef는 주로 클래스 컴포넌트에서 ref를 생성하는 데 사용되고, useRef는 주로 함수형 컴포넌트에서 활용된다.
createRef는 호출될 때마다 새로운 ref 객체를 반환하지만, useRef는 각 렌더링 사이클마다 동일한 ref 객체를 유지한다.
createRef는 초기 세팅 값을 받지 않아서 ref의 현재 속성이 처음에는 무조건 null로 설정된다. 반면, useRef는 초기값을 받을 수 있으며, ref의 현재 속성은 개발자가 지정한 값으로 초기화된다.
요약하자면, createRef는 클래스 컴포넌트에서 주로 쓰이며 호출될 때마다 새로운 ref를 생성한다.
반면, useRef는 함수형 컴포넌트에서 주로 사용되며 렌더링마다 동일한 ref를 반환한다. 그리고 initial 값을 지정할 수 있다.
해당 노드 인스턴스에 focus() 메서드를 이용해서 엘리먼트에 포커스를 줄 수 있다.
InputModal 컴포넌트에서는 사용자가 이미 설정된 값을 수정할 수 있는데 InputModal이 열릴 때 입력란에 자동으로 포커스가 있으면 좀 더 사용자 친화적 UI가 된다.
이때, input 엘리먼트에 대한 참조를 얻어야 한다.
그리고 InputModal이 마운트될 때 useEffect 훅 내에서 input 엘리먼트에 대해 자동으로 포커스를 맞춘다.
이렇게 하면 InutModal을 열 때 텍스트 상자에 기본적으로 포커스가 설정된다.
참고로 input 엘리먼트의 current 속성을 통해 엘리먼트에 액세스해야 한다.
사용자가 모달 외부를 클릭했을 때 모달 컴포넌트를 닫도록 만들 수도 있다.
다음은 이를 구현한 예제 코드이다.
여기서는 클릭된 요소가 모달의 영역을 벗어나는지 확인한다. 이로써 모달이 외부를 클릭했을 때, 추가 동작을 방지하고 onClose 콜백을 호출한다.
여기서 중요한 것은 바로 리액트에서의 상태(state) 변경은 비동기적(async)이기 때문에 DOM 요소의 현재 참조가 실제로 존재하는지 꼭 확인해야 한다.
마지막으로 document.body 요소에 전역 클릭 리스너를 추가하고, 해당 요소가 마운트 해제될 때는 리스너를 정리해야 한다.