useRef
1
const refContainer = useRef(initialValue);
useRef
는 .current
프로퍼티로 전달된 인자(initialValue
) 로 초기화된 변경 가능한 ref 객체를 반환한다. 변환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것이다.
일반적인 유스케이스는 자식에게 명령적으로 접근하는 경우:
1
2
3
4
5
6
7
8
9
10
11
12
13
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// 'current' points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" /> // input태그에 ref 훅을 달았다.
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
본질적으로 useRef
는 .current
프로퍼티에 변경 가능한 값을 담고있는 “상자” 같다.
Dom에 접근하는 방법으로 refs 를 사용할 수도 있다. <div ref={myRef} />
를 사용하여 React 로 ref 객체를 전달한다면, React 는 노드가 변경될 때마다 변경된 DOM 노드에 그것의 .current
프로퍼티를 설정할 것이다.
하지만, ref
속성보다 useRef()
가 더 유용하다. 이 기능은 클래스에서 인스턴스 필드를 사용하는 방법과 유사한 어떤 가변값을 유지하는데에 편리하다.
이것은 useRef()
가 순수 자바스크립트 객체를 생성하기 때문이다. useRef()
와 {current: ...}
객체 자체를 생성하는 것의 유일한 차이점이라면 useRef
는 매번 렌더링을 할 때 동일한 ref 객체를 제공한다는 것.
useRef
는 내용이 변경될 때 그것을 알려주지는 않는다 는 것을 주의하자. .current
프로퍼티를 변형하는 것이 리렌더링을 발생시키지는 않는다. React 가 DOM 노드에 ref를 attach 하거나 detach할 때 어떤 코드를 실행하고 싶으면 대신 콜백 ref
를 사용해야 한다.
실제로 사용해보기
JavaScript 를 사용 할 때, 특정 DOM 을 선택하는 상황에 getElementById
, querySelector
같은 DOM Selector 함수를 사용해서 DOM 을 선택함.
리액트에서도 가끔 DOM 을 직접 선택해야 하는 상황이 있다. 예를들어 특정 엘리먼트의 크기를 가져와야 한다던자ㅣ, 스크롤바 위치를 가져오거나 설정해야 된다던지, 포커스를 설정해줘야 한다던지 정말 다양한 상황이 있다.
리액트에서는 ref
를 사용하고, 함수형 컴포넌트에서 useRef
라는 Hook 함수를 사용.
초기화 버튼을 클릭했을 때 이름 input 에 포커스가 잡히도록 useRef
를 사용해보겠다.
InputSample.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import React, { useState, useRef } from "react";
function InputSample() {
const [inputs, setInputs] = useState({
name: "",
nickname: "",
});
const nameInput = useRef(null); // initialState 에 대해서 null값으로 설정해준다.
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value, // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: "",
nickname: "",
});
nameInput.current.focus();
};
return (
<div>
<input
name="name"
placeholder="이름"
onChange={onChange}
value={name}
ref={nameInput}
/>
<input
name="nickname"
placeholder="닉네임"
onChange={onChange}
value={nickname}
/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
useRef()
를 사용하여 Ref 객체를 만들고, 이 객체를 우리가 선택하고 싶은 DOM 에 ref
값으로 설정해주어야 한다. 그러면, Ref 객체의 .current
값은 우리가 원하는 DOM 을 가리키게 된다.
useRef 로 컴포넌트 안의 변수 만들기
컴포넌트에서 특정 DOM 을 선택해야 할 때, ref
를 사용했었다. 함수형 컴포넌트에서는 이를 설정 할 때, useRef
를 사용해서 설정했었다.
useRef
Hook 은 DOM을 선택하는 용도 외에도 다른용도가 한가지 더 있다. 컴포넌트 안에서 조회 및 수정할 수 있는 변수를 관리하는 것!
useRef
로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링 되지 않는다. 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회할 수 있는 반면, useRef
로 관리하고 있는 변수는 설정 후 바로 조회 가능.
이 변수를 사용하여 다음과 같은 값을 관리할 수 있음!
setTimeout
,setInterval
을 통해서 만들어진id
- 외부 라이브러리를 사용하여 생성된 인스턴스
- scroll 위치
1
2
3
4
5
6
7
8
9
// id 의 예시
const nextId = useRef(4);
const onCreate = () => {
// 나중에 구현 할 배열에 항목 추가하는 로직
// ...
nextId.current += 1;
};
onCreate 함수를 실행할 때 마다 nextId 는 +1 이 된다.
useRef()
를 사용할 때 파라미터를 넣어주면, 이 값이 .current
값의 기본값이 된다. 조작을 원하면 current값을 수정하거나, 조회를 하면 된다.
useRef 로 만들어진 객체는 React가 만든 전역 저장소에 저장되기 때문에 함수를 재 호출하더라도 마지막으로 업데이트한 current 값이 유지된다.
어디서 사용할까…?
useRef 는 값을 저장하기는 하지만, 리렌더가 필요하거나 값이 변경되면 리렌더가 필요할 때는 적합하지 않다. 전역저장소에 저장되면서 리렌더를 유발하지 않는것을 잘 활용하자.
- 컴포넌트 안에서 조회 및 수정 할 수 있는 변수 관리
- useRef로 관리되는 변수는 값이 바뀌어도 컴포넌트가 리렌더링 되지 않습니다.
- 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회 할 수 있는 반면, useRef 로 관리하고 있는 변수는 설정 후 바로 조회 할 수 있습니다.
참조
React 공식문서, https://react.vlpt.us/basic/10-useRef.html https://react.vlpt.us/basic/12-variable-with-useRef.html