createRef()와 useRef()의 차이점
createRef
: 클래스형 컴포넌트에서 사용
useRef
: 함수형 컴포넌트에서 사용
- 클래스형 컴포넌트는 인스턴스를 생성 후 render 코드 블록 쪽만 리랜더링후 다시 실행
- 함수형 컴포넌트는 함수 블록 안에 있는 모든 것을 리랜더링시 마다 다시 실행
- 함수형 컴포넌트에서 createRef를 사용 할 시 ref 값이 초기화 되어서 원하는 값을 얻지 못하기 떄문에, 리액트 훅인 useRef를 사용: 리액트 훅을 사용하면 useState 값을 리랜더링 할 때 내부적으로 값을 기억하듯이 useRef도 내부적으로 ref 값을 기억함.
useRef Hook
React 컴포넌트는 기본적으로 내부 상태(state)가 변할 때 마다 다시 랜더링(rendering)이 된다. 컴포넌트 함수가 다시 호출이 된다는 것은 함수 내부의 변수들이 모두 초기화가 되고 함수의 모든 로직이 다시 실행된다는 것을 의미한다.
다시 렌더링 되어도 동일한 참조값을 유지하려면?
리렌더링 시 함수 내부의 변수들이 기존에 저장하고 있는 값들을 잃어버리고 초기화되는데, 간혹 다시 랜더링이 되더라도 기존에 참조하고 있던 컴포넌트 함수 내의 값이 그대로 보존되야 하는 경우가 있다.
useRef
는 current 속성을 가지고 있는 객체를 반환하는데, 인자로 넘어온 초기값을 current 속성에 할당한다. 이 current 속성은 값을 변경해도 상태를 변경할 때처럼 React 컴포넌트가 다시 랜더링되지 않는다. React 컴포넌트가 다시 랜더링될 때도 마찬가지로 이 current 속성의 값이 유실되지 않는다.
useRef()를 사용하는 경우
DOM 노드나 React 엘리먼트에 직접 접근하기 위해서
React의
ref
prop은 HTML 엘리먼트의 레퍼런스를 변수에 저장하기 위해서 사용한다.예를 들어, 다음과 같이
<input>
엘리먼트에ref
prop으로inputRef
라는 변수를 넘기게 되면, 우리는 이inputRef
객체의current
속성을 통해서<input>
엘리먼트에 접근할 수 있고, DOM API를 이용하여 제어할 수 있습니다.1
<input ref={inputRef} />
- input 엘리먼트 제어
- audio 엘리먼트 제어
useRef에 ref element들을 할당해야 하므로 배열로 초기값 선언
객체를 할당해도 된다.
1
const refs = useRef([]);
위와 같이 빈 배열(객체)을 전달하면, 여러개의 DOM element를 refs에 담을 수 있다.
1
2
3
4
5
6<div>
<div ref={el => (refs.current[0] = el)} />
<div ref={el => (refs.current[1] = el)} />
<div ref={el => (refs.current[2] = el)} />
<div ref={el => (refs.current[3] = el)} />
</div>- 각 div의 ref에는 useRef 자체가 아니라 useRef 배열의 index를 설정해주어야 한다.
- 객체를 할당할 때에는 property로 접근하면 된다.
할당한 객체에 맞게 접근하기 위해, ref.current에서 배열의 index나 객체의 property를 이용하여 접근한다.
1
refs.current[currentInput]
Uncontrolled Component 문제
1 | function CustomTextInput(props) { |
- 관리해야 할 엘리먼트들이 늘어날수록, 정의해야 할 useRef 또한 정비례하여 증가하게 된다.
useRef를 정의하는 곳과 사용하는 곳이 한 곳에 존재하면, react hooks의 특성상 동적으로 그 개수를 늘려가며 선언할 수 없다. 반면 방법1과 방법2에서는 동적으로 늘어나도 동일한 매커니즘으로 동작할 수 있다.
해결 방안1. Controlled Component + Uncontrolled Component
- 리액트스러움: DOM을 제어하는 부분을 가려둔채 컴포넌트로만 보게 되면, CustomTextInput 를 사용하는 입장에서 내부 구현을 알 수 없는채로 “무엇”이 나타나길 기대하며 그 방법을 알지 못해도 된다는 점에서 “선언적”이라고 볼 수 있다.
1 | function CustomTextInput({focused}) { |
- useRef를 관리할 엘리먼트 수만큼 정의해야 하는 단점이 있지만, 이 경우에 그 기능이 각 컴포넌트와 props로 가려지기 때문에 복잡한 상태를 최소한의 노력으로 관리할 수 있다.
해결 방안2. Uncontrolled Component
- 한정된 기능만 제공: 해당 컴포넌트를 “어떻게” 제어해야 하는지 그대로 노출하고 있다.
1 | function Form({focused}) { |