useRef()의 대표적인 사용 방법을 정리하면서 어떻게 사용할 수 있는지 알아본다.
특정 DOM 선택
컴포넌트 안에 변수 관리
컴포넌트 전 생애주기에 유지되는 특성을 통해 설정 후 즉시 조회 가능한 변수로 관리가 가능하며, 다음과 같은 값을 관리 할 수 있다.
setTimeout
, setinterval
을 통해 만들어진 id리렌더링 방지
리렌더링을 트리거 하지 않는 특성을 통해 onChange 등을 대신해 리렌더링을 방지할 수 있다.
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useRef
는 current
라는 속성을 가지며, ref
를 속성으로 가지는 요소가 current
에 할당된다.
위의 코드에서 버튼을 클릭하면 inputEl
을 할당받은 ref
속성을 가지는 요소에 포커스가 잡히게 된다.
위에서 소개한 3가지 상황등 다양한 사용법이 있지만 여기서는 id
를 관리하는 상황을 소개한다.
어떤 상태 객체를 map()
을 사용해 li
요소로 생성하는 상황 등 추가되는 데이터에 id
가 있기를 바라는 경우 useRef()
를 통해 uuid를 대신해 볼 수 있다.
function App() {
const [user, setUser] = useState([
{id: 1, name: 'john'},
{id: 2, name: 'sam'}
]);
const [inputName. setInputName] = useState('');
const idRef = useRef(user.length+1);
// ref의 초기값으로 숫자를 설정해 아래에서 id 값으로 사용한다.
const handleChange = (e) => {
setInputName(e.target.value);
};
const handleClick = () => {
setUser([...user, {id: idRef.current, name: inputName}])
idRef.current += 1; {/*id값을 할당한 후 증가 시킨다. ref는 렌더링이 발생해도 초기화 되지 않으므로 다시 데이터를 추가할 때 id 값이 중복되지 않는다.*/}
};
return (
<>
<ul>
{user.map(e=><li key={e.id}>{e.name}</li>)}
</ul>
<input
type='text'
value={inputName}
onChange={(e)=>handleChange(e)}
/>
<button onClick={handleClick}>click</button>
</>
)
}
id
를 관리할 변수를 useRef를 통해 선언하고 초기값으로 user.length+1로 지정해주면 처음 추가할 데이터의 id
가 설정되고 이후 추가하는 이벤트에 1씩 더해 중복되지않는 id를 할당할 수 있다.
위 내부 변수 관리에서 onChange
이벤트는 input에 입력이 있을 때마다 state
를 업데이트해서 많은 렌더링을 불러 일으킨다.
이러한 상황에서 onChange의 setState
를 렌더링을 일으키지 않는 useRef
로 대체해 리렌더링을 방지할 수 있다.
function App() {
const [user, setUser] = useState([
{id: 1, name: 'john'},
{id: 2, name: 'sam'}
]);
const idRef = useRef(user.length+1);
const nameRef = useRef(null);
const handleClick = () => {
setUser([...user, {id: idRef.current, name: nameRef.current.value}]);
idRef.current += 1;
nameRef.current.value = '';
};
return (
<>
<ul>
{user.map(e=><li key={e.id}>{e.name}</li>)}
</ul>
<input
type='text'
ref={nameRef}
/>
<button onClick={handleClick}>click</button>
</>
)
}
가져올 input
에 ref
를 설정하고, ref
를 통해서 최종 입력된 value
를 데이터 목록 state
에 추가할 수 있게 지정하면, input
입력 시에는 리렌더링이 일어나지 않게 된다.
React 공식문서에서는 ref의 바람직한 사용 사례로 다음의 세 가지 상황을 제시한다.
이 외에 React는 선언적으로 해결될 수 있는 문제에 대해서의 ref사용을 지양하고 있다.
Ref를 남용하지 마세요
ref는 애플리케이션에 “어떤 일이 일어나게” 할 때 사용될 수도 있습니다. 그럴 때는 잠시 멈추고 어느 컴포넌트 계층에서 상태를 소유해야 하는지 신중하게 생각해보세요. 대부분의 경우, 상태를 소유해야 하는 적절한 장소가 더 높은 계층이라는 결론이 날 겁니다.
-React 문서-
이는 React의 특징이자 이점인 선언적 코드에 ref
가 부합하지 않기 때문이다.
참고 사이트
React-문서-Ref와 DOM
React-문서-Hook API 참고서
벨로퍼트와 함께하는 모던 리액트-useRef로 컴포넌트 안의 변수 만들기
벨로퍼트와 함께하는 모던 리액트-배열에 항목 추가하기
velog-kysung95-[짤막글] useRef가 뭔가요?
github.io-deeming-김민지-useRef는 처음이라 :: 개념부터 활용 예시까지