React Hooks: useRef

React Hooks 중에서 useState() useEffect() 처럼 많이 쓰이지는 않지만 가끔 나와서 햇갈리게 하는 녀석이 있습니다. 바로 useRef() 훅(hook) 함수인데요. 이번 포스팅에서는 useRef() 함수가 왜 필요하고, 언제 사용하는지에 대해서 알아보겠습니다.

 

상태 변경 -> 컴포넌트 재 랜더링

React 컴포넌트는 기본적으로 내부 상태(state)가 변할 때 마다 다시 랜더링(rendering)이 됩니다.

예를 들어, 아래 <Counter/> 컴포넌트의 버튼을 5번 클릭하면 count 상태값은 5번 바뀌게 됩니다.

 

import React, { useState } from "react";

function Counter() {
  const [count, setCount] = useState(0);
  console.log(`랜더링... count: ${count}`);

  return (
    <>
      <p>{count}번 클릭하셨습니다.</p>
      <button onClick={() => setCount(count + 1)}>클릭</button>
    </>
  );
}

브라우저 콘솔을 확인해보면, 5번의 로그가 찍히는 것을 볼 수 있는데요. 이를 통해, <Counter/> 컴포넌트 함수는 count 상태가 바뀔 때 마다 호출되는 것을 알 수 있습니다.

랜더링... count: 1
랜더링... count: 2
랜더링... count: 3
랜더링... count: 4
랜더링... count: 5

컴포넌트 함수가 다시 호출이 된다는 것은 함수 내부의 변수들이 모두 다시 초기화가 되고 함수의 모든 로직이 다시 실행된다는 것을 의미

 

useRef 사용하기

useRef 함수는 current 속성을 가지고 있는 객체를 반환하는데, 인자로 넘어온 초기값을 current 속성에 할당합니다. 이 current 속성은 값을 변경해도 상태를 변경할 때 처럼 React 컴포넌트가 다시 랜더링되지 않습니다. React 컴포넌트가 다시 랜더링될 때도 마찬가지로 이 current 속성의 값이 유실되지 않습니다.

useRef 훅 함수가 반환하는 객체의 이러한 독특한 성질을 이용하여 startCounter()와 stopCounter() 함수를 구현해보았습니다.

 

import React, { useState, useRef } from "react";

function ManualCounter() {
  const [count, setCount] = useState(0);
  const intervalId = useRef(null);
  console.log(`랜더링... count: ${count}`);

  const startCounter = () => {
    intervalId.current = setInterval(
      () => setCount((count) => count + 1),
      1000
    );
    console.log(`시작... intervalId: ${intervalId.current}`);
  };

  const stopCounter = () => {
    clearInterval(intervalId.current);
    console.log(`정지... intervalId: ${intervalId.current}`);
  };

  return (
    <>
      <p>자동 카운트: {count}</p>
      <button onClick={startCounter}>시작</button>
      <button onClick={stopCounter}>정지</button>
    </>
  );
}

컴포넌트를 브라우저에서 실행하면 콘솔에 아래와 같은 로그가 찍히는데요. 시작 버튼을 누르면 새로운 intervalId가 생성되고, 정지 버튼을 누르면 기존 intervalId가 정리되는 것을 확인할 수 있습니다.

 

랜더링... count: 0
시작... intervalId: 17
랜더링... count: 1
랜더링... count: 2
랜더링... count: 3
랜더링... count: 4
랜더링... count: 5
정지... intervalId: 17
시작... intervalId: 32
랜더링... count: 6
랜더링... count: 7
랜더링... count: 8
정지... intervalId: 32

전체 코드

본 포스팅에서 작성한 코드는 아래에서 확인하시고 직접 실행해보실 수 있습니다. <Counter />, <AutoCounter/>, <ManualCounter/>을 동시에 실행하지 마시고, 하나씩 실행하시면 콘솔에서 로그를 확인하는 게 수월하실 겁니다.

 

참조<DaleSeo>

'codestates' 카테고리의 다른 글

웹표준  (0) 2022.07.11
CSS in JS  (0) 2022.06.30
UI & UX  (0) 2022.06.27
mini Job-Searching  (0) 2022.06.22
Effect Hook 사용하기  (0) 2022.06.20