[React] Hooks (3) - useRef, 커스텀 훅

invisibleVoice·2025년 2월 3일

리액트

목록 보기
10/14
post-thumbnail

useRef

useRef는 리렌더링과 상관없이 값을 기억하기 위해 사용된다. 다시 말해, 컴포넌트가 계속 렌더링 되어도 언마운트 전까지 값을 유지한다.
ref는 크게 두 가지 용도로 사용된다. state와 비슷한 역할을 하지만 ref에 저장한 값은 변경되더라도 렌더링을 일으키지 않기 때문에 리렌더링을 발생시키지 않는 값을 저장할 때, 또는 DOM 요소를 핸들링해야 하는 순간이다.

  • 리렌더링을 발생시키지 않는 값 저장
import "./App.css";
import { useRef, useState } from "react";

function App() {
  const [count, setCount] = useState(0);
  const countRef = useRef(0);

  const plusStateCountButtonHandler = () => {
    setCount(count + 1);
  };

  const plusRefCountButtonHandler = () => {
    countRef.current++;
  };

  return (
    <>
      <div>
        state ===> {count} <br />
        <button onClick={plusStateCountButtonHandler}>state 증가</button>
      </div>
      <div>
        ref ===> {countRef.current} <br />
        <button onClick={plusRefCountButtonHandler}>ref 증가</button>
      </div>
    </>
  );
}

export default App;

plusStateCountButtonHandler의 경우 상태가 변경될 때마다 리렌더링이 되어 화면에 변경된 값이 표시된다. 반면 plusRefCountButtonHandler 아무리 눌러도 화면에는 변화가 없다. 리렌더링이 되지 않기 때문이다. 물론 ref에 저장한 값은 계속 변하고 있다! 화면에 표시가 안 될 뿐이다. ref버튼을 잔뜩 누르고 state버튼을 누르면 그제서야 리렌더링 되어 잔뜩 증가한 ref값이 화면에 표시될 것이다!

  • DOM 요소 핸들링
function App() {
  const inputRef = useRef(null);

  const handleClick = () => {
    inputRef.current.focus(); // 🔥 직접 DOM 요소에 접근 가능
  };

  return (
    <>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>포커스 이동</button>
    </>
  );
}

ref속성을 이용하면 직접 DOM 요소에 접근할 수 있다. querySelector없이도 특정 요소를 참조할 수 있다. 다만, 직접 DOM을 조작하는 것은 리액트가 지향하는 선언적 방식과는 맞지 않아 꼭 필요한 경우에만 사용해야 한다.

커스텀 훅

커스텀 훅은 훅을 모아놓은 훅이라고 볼 수 있다. 반복되는 로직이나 중복되는 코드를 커스텀 훅을 통해 관리할 수 있다.

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

const App = () => {
  // input의 갯수가 늘어날때마다 state와 handler가 같이 증가한다.
  const [title, setTitle] = useState("");
  const onChangeTitleHandler = (e) => {
    setTitle(e.target.value);
  };

  const [body, setBody] = useState("");
  const onChangeBodyHandler = (e) => {
    setBody(e.target.value);
  };

  return (
    <div>
      <input
        type="text"
        name="title"
        value={title}
        onChange={onChangeTitleHandler}
      />
      <input
        type="text"
        name="title"
        value={body}
        onChange={onChangeBodyHandler}
      />
    </div>
  );
};

export default App;

상태가 늘어날때마다 핸들러가 늘어나는데, 이름만 다를 뿐 로직은 똑같다. 이렇게 반복되는 코드들을 커스텀 훅을 이용해 정리할 수 있다.

보통 커스텀 훅은 Hooks라는 폴더 안에 관리하고 파일명은 use로 시작하는 것이 관례이다.

// src/hooks/useInput.js
import React, { useState } from "react";

const useInput = () => {
  const [value, setValue] = useState("");
  const handler = (e) => {
    setValue(e.target.value);
  };

  return [value, handler];
};

export default useInput;
// src/App.jsx
import React from "react";
import useInput from "./hooks/useInput";

const App = () => {
  
  const [title, onChangeTitleHandler] = useInput();
  const [body, onChangeBodyHandler] = useInput();

  return (
    <div>
      <input
        type="text"
        name="title"
        value={title}
        onChange={onChangeTitleHandler}
      />

      <input
        type="text"
        name="title"
        value={body}
        onChange={onChangeBodyHandler}
      />
    </div>
  );
};

export default App;

커스텀 훅을 마치 원래 있던 훅처럼 사용할 수 있다!

profile
게임 QA 이직 준비중

0개의 댓글