React - useRef Hook

Khan·2022년 9월 24일
0

TIL

목록 보기
12/19
post-thumbnail

useRef가 무엇인가요?

useRef는 .current프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref객체를 반환합니다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것입니다. 본질적으로 useRef는 .current프로퍼티에 변경 가능한 값을 담고 있는 상자와 같습니다.

React 공식 문서에 적혀 있는 useRef 정의입니다. useRef 사용 예제를 통해 위 정의에 대해 자세히 알아보겠습니다.

useRef VS document.querySelector

지양하는 이유

  1. document.querySelector를 사용하면 직접 DOM에 접근하여 실제 DOM Element에 접근 하게 된다. 하지만 React는 Virtual DOM을 사용하여 Real DOM을 그리는데, DOM API로 Real DOM에 있는 Element에 접근 하였는데 이게 현재 Virtual DOM을 통해 Real DOM에 존재하는 친구인지 아닌지 확신할 수 없다

  2. React 시스템을 벗어나 DOM을 직접적으로 건드리게되면 React가 제어하는 영역에서 벗어나게 된다. React가 제어하지 않는 영역에서 State 값을 조작할 경우 React의 Lifecycle에 맞추어 DOM Element를 가져오지 못해 가져온 DOM Element를 신뢰할 수 없어지는 문제가 발생한다. 이렇게 데이터를 어디에서 어떻게 조작하고 있는지 예측하기 어렵기 때문에 디버깅 또한 어려워진다.

useRef는 언제 사용할까?

특정 DOM을 선택할 때

  • 예를 들어서 특정 엘리먼트의 크기를 가져와야 한다던지, 스크롤바 위치를 가져오거나 설정해야된다던지, 또는 포커스를 설정해줘야된다던지 등 정말 다양한 상황에서 사용된다.
  • Video.js, JWPlayer 같은 HTML5 Video 관련 라이브러리, 또는 D3, chart.js 같은 그래프 관련 라이브러리 등의 외부 라이브러리를 사용해야 할 때에도 특정 DOM 에다 적용하기 때문에 DOM 을 선택해야 하는 상황이 발생 할 수 있습니다.

    함수형 컴포넌트 = ref를 사용할때에는 useRef()라는 Hook 함수를 사용한다.
    클래스형 컴포넌트 = 콜백 함수를 사용하거나 React.createRef 라는 함수를 사용한다.

컴포넌트 안의 변수 만들 때

  • useRef로 변수를 관리하게 되면 그 변수가 업데이트 된다고 해서 컴포는트가 리렌더링 되지 않는다. 즉 굳이 리렌더링 할 필요가 없는 변수라면 useRef로 관리해주는 것이 효율적이다.
    이 변수를 사용하여 다음과 같은 값을 관리할 수 있습니다.
    • 이 변수를 사용하여 다음과 같은 값을 관리할 수 있습니다.
      • setTimeout, setInterval을 통해서 만들어진 id
      • 외부 라이브러리를 사용하여 생성된 인스턴스
      • scroll위치
// 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의 리렌더링을 방지해야 할 때

위 예시 코드에는 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 선택하기

0개의 댓글