React, Next, Redux/🚀 React with Hooks

React Hooks : useRef(), ref

DarrenKwonDev 2020. 3. 22. 18:57
 

Hooks API Reference – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

React Hooks : useRef() 함수

자바스크립트에서 특정 DOM 을 선택해야할 때는 DOM Selector를 사용한다. 리액트 프로젝트에서도 특정 요소의 크기를 가져온다거나, 포커스를 설정해야한다거나 특정 DOM을 선택해야할 상황이 있다. 이런 경우,..

xiubindev.tistory.com

 

useRef() 훅을 사용할 수 없는 클래스형 컴포넌트의 경우에는 React.createRef()를 사용합니다.

 

  • ref + useRef()

useRef나 ref는 getElementById()나 querySelector()와 같은 역할을 한다. 해당 컴포넌트나 태그를 조작할 수 있게 되는 것이다. 

 

그러면 왜 직접 jsx 내부 내그에 id를 넣고, getElement... 를 통해 직접 DOM을 조작하지 않는가? => 컴포넌트의 주된 이점인 '재활용'에서 id가 겹치므로.

 

<input> 이란 태그가 potato라는 식별자에 담기도록 useRef를 통해 지정해주었습니다.

 

import React, { useRef } from "react";

const App = () => {
  const potato = useRef();
  setTimeout(() => console.log(potato), 3000);
  return (
    <>
      <div>
        <h1>TEST</h1>
        <input ref={potato} placeholder="Yeah!"></input>
      </div>
    </>
  );
};

export default App;

 

potato를 출력해보니 객체에 input태그가 담겨 있습니다.

 

  • 그래서 이걸 어디에 써먹을까?

앞서 말했듯 useRef와 ref는 getElementById()나 querySelector()와 같은 역할을 한다. 따라서 해당 태그에 대해 조작할 수 있다. state만으로는 조작할 수 없는 기능들은 useRef를 써서 조작해야 합니다.

 

대표적인 예로

특정 input에 포커스 주기 (포커스)

스크롤 박스 조작하기 (스크롤에 관한 것)

Canvas 요소에 그림그리기가 있습니다. (캔버스)

 

가급적 포커스, 스크롤, 캔버스가 아니면 state를 활용하고, 이 세 경우에만 ref를 사용하도록 합시다.

 

(+ form/input 에서 DOM 조작을 통해서 다른 버튼을 눌러 업로드하는 방식도 useRef를 쓰는 것이 좋습니다.)

 

클릭하면 input에 포커스가 되도록 만들어 보았습니다.

import React, { useRef } from "react";

const App = () => {
  const potato = useRef();

  const handleClick = () => {
    potato.current.focus();
  };

  return (
    <>
      <div>
        <h1>TEST</h1>
        <input ref={potato} placeholder="Yeah!"></input>
        <button onClick={handleClick}>포커스!</button>
      </div>
    </>
  );
};

export default App;

 

 

 

 

 


 

ref의 대상은 태그가 아니라 클래스형 컴포넌트에도 가능합니다. (함수형 컴포넌트는 안됩니다)

 

import React, { useRef } from "react";

class Test extends React.Component {
  render() {
    return <div>what</div>;
  }
}

const App = () => {
  const potato = useRef();
  setTimeout(() => console.log(potato), 3000);
  return (
    <>
      <div>
        <h1>TEST</h1>
        <Test ref={potato} />
      </div>
    </>
  );
};

export default App;

 


tip! 

 

Note that useRef() is useful for more than the ref attribute. It's handy for keeping any mutable value around similar to how you'd use instance fields in classes

 

useRef는 보통 특정 DOM을 선택, 조작해야할 때 사용한다고 알려져 있지만, 꼭 그렇지만은 않습니다. useRef를 생성한 후 ref를 컴포넌트에 붙이지 않고 사용할 수도 있습니다. 값이 바뀌어도 화면이 리렌더링되지 않게 하기 위해서 사용하는 경우도 있습니다. (그리고 아시다시피 js에서는 함수도 값처럼 취급하므로 변수로 지정할 수 있습니다. )

 

이를 이용해서 다음과 같이 정의해보려고 했습니다. js에서는 아무 문제 없이 돌아가는 코드가.. TS에서는 작동하지 않습니다. 이러한 이유는 useRef의 3가지 종류 중 적절한 것을 사용하지 못했기 때문입니다.

const timeout = useRef(null);

timeout.current = setTimeout(() => {
  startTime.current = new Date().getTime();
}, Math.floor(Math.random() * 1000) + 2000);