useRef는 .current프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다. 본질적으로 useRef는 .current프로퍼티에 변경 가능한 값을 담고 있는 상자와 같습니다.
React 공식 문서에 적혀 있는 useRef 정의입니다. useRef 사용 예제를 통해 위 정의에 대해 자세히 알아보겠습니다.
document.querySelector를 사용하면 직접 DOM에 접근하여 실제 DOM Element에 접근 하게 된다. 하지만 React는 Virtual DOM을 사용하여 Real DOM을 그리는데, DOM API로 Real DOM에 있는 Element에 접근 하였는데 이게 현재 Virtual DOM을 통해 Real DOM에 존재하는 친구인지 아닌지 확신할 수 없다
React 시스템을 벗어나 DOM을 직접적으로 건드리게되면 React가 제어하는 영역에서 벗어나게 된다. React가 제어하지 않는 영역에서 State 값을 조작할 경우 React의 Lifecycle에 맞추어 DOM Element를 가져오지 못해 가져온 DOM Element를 신뢰할 수 없어지는 문제가 발생한다. 이렇게 데이터를 어디에서 어떻게 조작하고 있는지 예측하기 어렵기 때문에 디버깅 또한 어려워진다.
함수형 컴포넌트 = ref를 사용할때에는 useRef()라는 Hook 함수를 사용한다.
클래스형 컴포넌트 = 콜백 함수를 사용하거나 React.createRef 라는 함수를 사용한다.
// App.jsx
import { useRef, useState } from 'react';
import UserList from './UserList';
function App() {
const nextId = useRef(4);
const [usernameValue, setUsernameValue] = useState('');
const [users, setUsers] = useState([
{id: 1, username: 'user1',},
{id: 2, username: 'user2',},
{id: 3, username: 'user3',}
]);
const onChange = ({ target }) => setUsernameValue(target.value);
const onCreate = () => {
if(!usernameValue) return
const user = {
id: nextId.current,
username: usernameValue,
};
setUsers(users.concat(user));
setInputs('');
nextId.current += 1;
};
return (
<>
<div>
<input placeholder="이름" onChange={onChange} value={inputs.username} />
<button onClick={onCreate}>등록</button>
</div>
<UserList users={users} />
</>
);
}
export default App;
const nextId = useRef(4);
: 배열의 고유값 변수로 nextId를 설정해주고,
useRef() 파라타미터로 다음 id가 될 숫자 4를 넣어준다.
파라미터 값을 넣어주면 해당 값이 변수의 current 값이 된다.
그리고 nextId 변수를 수정하거나 조회려면 .current 값을 수정하거나 조회한다.
nextId.current += 1;
: nextId 변수에 1씩 더하여 업데이트를 한다.
위 예시 코드에는 input값이 변경될 때마다 리렌더링 된다는 단점이 있습니다.
onChange구현 부분을 ref값으로 대체해서 단점을 해결할 수 있습니다. state로 event의 value에 접근하지 않고 refObject.current.value를 사용하는 방법입니다.
import { useRef } from 'react';
import UserList from './UserList';
function App() {
const nextId = useRef(4);
const usernameRef = useRef('');
const [users, setUsers] = useState([
{id: 1, username: 'user1',},
{id: 2, username: 'user2',},
{id: 3, username: 'user3',}
]);
const onCreate = () => {
const user = {
id: nextId.current,
username: usernameRef.current.value,
};
setUsers(users.concat(user));
nextId.current += 1;
};
console.log('Render');
return (
<>
<div>
<input placeholder="이름" ref={usernameRef} />
<button onClick={onCreate}>등록</button>
</div>
<UserList users={users} />
</>
);
}
export default App;
처음 App 컴포넌트를 불러왔을 때, 등록 버튼을 눌렀을 때 2번만 렌더링 되는 것을 확인할 수 있습니다.
Hooks API Reference
React Hooks : UseRef() 함수
useRef 로 특정 DOM 선택하기