useRef() 사용 방법

Rosevillage·2023년 2월 21일
0

useRef()의 대표적인 사용 방법을 정리하면서 어떻게 사용할 수 있는지 알아본다.

useRef() 사용 방법

  • 특정 DOM 선택

  • 컴포넌트 안에 변수 관리
    컴포넌트 전 생애주기에 유지되는 특성을 통해 설정 후 즉시 조회 가능한 변수로 관리가 가능하며, 다음과 같은 값을 관리 할 수 있다.

    • setTimeout, setinterval을 통해 만들어진 id
    • 외부 라이브러리를 통해 생성된 인스턴스
    • scroll 위치
  • 리렌더링 방지
    리렌더링을 트리거 하지 않는 특성을 통해 onChange 등을 대신해 리렌더링을 방지할 수 있다.

1. 특정 DOM 선택

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

useRefcurrent라는 속성을 가지며, ref를 속성으로 가지는 요소가 current에 할당된다.
위의 코드에서 버튼을 클릭하면 inputEl을 할당받은 ref속성을 가지는 요소에 포커스가 잡히게 된다.

2. 컴포넌트 내부 변수 관리

위에서 소개한 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를 할당할 수 있다.

3. 리렌더링 방지

위 내부 변수 관리에서 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>
   </>
 )
}

가져올 inputref를 설정하고, ref를 통해서 최종 입력된 value를 데이터 목록 state에 추가할 수 있게 지정하면, input 입력 시에는 리렌더링이 일어나지 않게 된다.

Ref 주의사항

React 공식문서에서는 ref의 바람직한 사용 사례로 다음의 세 가지 상황을 제시한다.

  • 포커스, 텍스트 선택영역, 혹은 미디어의 재생을 관리할 때.
  • 애니메이션을 직접적으로 실행시킬 때.
  • 서드 파티 DOM 라이브러리를 React와 같이 사용할 때.

이 외에 React는 선언적으로 해결될 수 있는 문제에 대해서의 ref사용을 지양하고 있다.

Ref를 남용하지 마세요
ref는 애플리케이션에 “어떤 일이 일어나게” 할 때 사용될 수도 있습니다. 그럴 때는 잠시 멈추고 어느 컴포넌트 계층에서 상태를 소유해야 하는지 신중하게 생각해보세요. 대부분의 경우, 상태를 소유해야 하는 적절한 장소가 더 높은 계층이라는 결론이 날 겁니다.
-React 문서-

이는 React의 특징이자 이점인 선언적 코드에 ref가 부합하지 않기 때문이다.


참고 사이트

React-문서-Ref와 DOM

React-문서-Hook API 참고서

벨로퍼트와 함께하는 모던 리액트-useRef로 컴포넌트 안의 변수 만들기

벨로퍼트와 함께하는 모던 리액트-배열에 항목 추가하기

velog-kysung95-[짤막글] useRef가 뭔가요?

github.io-deeming-김민지-useRef는 처음이라 :: 개념부터 활용 예시까지

0개의 댓글