리액트 useRef 정리

버건디·2022년 12월 6일
0

리액트

목록 보기
30/58
post-thumbnail

🔍 Ref 란 ?

Ref는 references (참조) 라는 뜻이다.

원래 리액트의 ref는 특정 요소에 접근하는데 사용하는 props 인데, 리액트에서 DOM에 접근하고자 할때 사용한다.

HTML 에서 태그에 id 값을 부여하고, 자바스크립트에서 getElementById 로 그 id 에 접근해서 DOM 을 조작하는 것처럼, ref에 값을 줌으로써 DOM에 접근할 수 있다.

🔍 왜 리액트에서는 id 값을 주면 안될까?

리액트에서는 jsx 문법을 이용해서 컴포넌트들을 작성하고, 그 컴포넌트들을 재사용한다.

만약에 HTML 과 같이 아이디값이 존재한다면, 그 컴포넌트들이 재사용 될때마다 id값을 가진 요소가 재렌더링 될것이고, 이렇게 된다면 동일 아이디를 가진 요소들이 여러개가 생기기 때문에 리액트에서는 id 값 대신 Ref 를 사용한다.

즉 리액트에서 컴포넌트나 엘레먼트의 id 역할을 하는것이 Ref 이다.


🔍 useRef 란?

리액트 공식문서에서 useRef 를 위와 같이 정의하고 있지만, 이해가 되지 않았다.

다른 여러 글들과 영상들을 참고해서 저 공식문서 문구들을 해석해보았다.

useRef 는 함수형 컴포넌트에서 사용되는 Hook 인데, ref 객체를 리턴한다.

import { useRef } from "react";

function App() {
  const inputEl = useRef('');

  console.log("inputEl : ", inputEl);

  return <></>;
}

export default App;

보면 current 라는 key 를 가진 객체가 반환되는 것을 볼 수 있다.

저 current 는 useRef() 안에 넣어준 초깃값이다.

current 값을 조작해서 초깃값을 수정해줄 수 도 있다.

import { useRef } from "react";

function App() {
  const inputEl = useRef('');

  inputEl.current = 1;

  console.log(inputEl);

  return <></>;
}

export default App;


반환된 ref 는 컴포넌트의 전 생애주기를 통해 유지가 된다.

라는 말은 컴포넌트가 계속해서 재렌더링이 되어도, 컴포넌트가 언마운트 되기 전까지 (즉, 화면에서 사라지기 전까지 )는 값을 그대로 유지할 수 가 있다.

🔍 useRef 는 언제 사용할까?

1. state 와 비슷하게 어떠한 값을 저장해 둘때 사용한다.

그럼 useState 와 useRef 의 차이점은 어떤것인가?

useState 를 사용할때, state 값이 변경 될때마다 재렌더링이 발생한다.

또한 함수형 컴포넌트는 말그대로 함수이기 때문에, 함수가 불려진 후에는 함수 안의 변수들이 다시 초기화가 된다.

하지만 useRef 를 사용하면 Ref 안의 값들이 아무리 변경되어도, 재렌더링이 발생하지 않고 컴포넌트 안의 변수 값들이 그대로 유지가 된다.

그렇기 때문에 state 대신 ref 를 사용한다면, 불필요한 렌더링을 막을 수 있다.

또한 state 를 사용해서 값을 변경해서 재렌더링이 발생하더라도 ref 안에 있는 값은 그대로 유지가 된다.

변경시 렌더링을 발생시키지 말아야할 값을 다룰때 용이하다.

2. DOM 에 접근할 때 사용한다.

위에 말했던것처럼 ref 를 이용하면 DOM에 접근할 수 있다.

대표적으로 input 요소를 클릭하지 않아도 focus 를 주고 싶을때 사용한다.

예를 들어 로그인 화면을 클릭했을때, 자동적으로 아이디를 입력하는 칸에 포커스를 줌으로써 편리하게 할 수 있다.


🔍 useState 와 useRef 비교해보기

import { useState } from "react";

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

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

  console.log("재렌더링이 됩니다.");

  return (
    <>
      <p>숫자 : {count}</p>
      <button onClick={setCountHandler}>값 변경</button>
    </>
  );
}

export default App;

버튼을 클릭할때마다 count state 값이 변경되도록했고, 렌더링이 될때마다 콘솔창이 띄어지도록 했다.

버튼을 클릭하면 저 콘솔창도 클릭한 수에 맞게 띄어졌는데,

즉 state 값이 변경될때마다 화면이 재렌더링 됐다.

import { useRef, useState } from "react";

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

  const countRef = useRef(0);

  const setCountHandler = () => {
    setCount(count + 1);
    console.log("count State의 값은", count);
  };

  console.log("재렌더링 됩니다.");

  const countRefHandler = () => {
    countRef.current = countRef.current + 1;
    console.log("countRef의 값은 ", countRef.current);
  };

  return (
    <>
      <p>State 값 : {count}</p>
      <button onClick={setCountHandler}>State 값 변경</button>
      <p>Ref 값 : {countRef.current}</p>
      <button onClick={countRefHandler}>Ref 값 변경</button>
    </>
  );
}

export default App;

useRef 를 사용한 버튼을 하나 더 추가해서 값을 비교해보았다.

처음에 새로고침을 누르면 "재렌더링 됩니다." 라는 콘솔창이 나왔고, state 변경 버튼을 누를때마다 재렌더링이 되었다.

하지만 ref 값 변경 버튼을 여러번 눌러도 재렌더링 콘솔창이 띄어지지 않았다.

재렌더링이 이루어지지 않았기 때문에 화면상에서도 Ref 값이 변경된것처럼 보이지 않았다.

state 값 변경 버튼을 한번 누르니, ref 값도 다시 재렌더링 된것을 확인할 수 있었다.

🔍 그렇다면 일반 변수에 값을 저장해서 사용할 수 있지 않을까?

import { useRef, useState } from "react";

function App() {
  const [render, setRender] = useState('');

  const countRef = useRef(0);

  let countNum = 0;

  const countRefHandler = () => {
    countRef.current += 1;
    console.log("ref 값 : ", countRef.current);
  };

  const setNumHandler = () => {
    countNum += 1;
    console.log("Num 값 : ", countNum);
  };

  const renderHandler = () => {
    setRender('렌더링 됐습니다.');
    console.log(render);
  };

  return (
    <>
      <button onClick={renderHandler}>렌더링 버튼</button>
      <p>Num 값 : {countNum}</p>
      <button onClick={setNumHandler}>State 값 변경</button>
      <p>Ref 값 : {countRef.current}</p>
      <button onClick={countRefHandler}>Ref 값 변경</button>
    </>
  );
}

export default App;

버튼을 3개 만들고, 하나는 useState 를 사용한 재렌더링을 위한 버튼,

하나는 ref 값 변경 버튼, 하나는 그냥 let 변수 값을 변경해주는 버튼이다.

밑의 사진은 렌더링 버튼을 누른후, 재렌더링이 된 후의 사진인데, Num 값은 변경이 되지 않았지만, Ref 값은 재렌더링이 되어서 값이 변경된 걸 볼수 있다.

그 이유는

재렌더링이 된다는 것은 함수 컴포넌트가 다시 호출 된다는 것이고, 다시 호출되면서 변수들이 초기화 되기 때문에

Num 값은 초깃값인 0 으로 다시 변경되므로 값이 변경되지 않는것이다.

또한 Num 값은 다시 초기화가 되어서 숫자가 다시 0부터 시작되지만, ref 는 그 값을 컴포넌트가 언마운트 되기 전까지 가지고 있으므로, 값이 누적된다.


🔍 useRef를 사용해서 DOM 에 접근하기

import { useEffect } from "react";
import { useRef } from "react";

function App() {
  const idRef = useRef();

  useEffect(() => {
    console.log(idRef);
  },[]);

  return (
    <>
      <input ref={idRef} type={"text"} placeholder="아이디"></input>
      <button>로그인</button>
    </>
  );
}

export default App;

아이디를 입력하는 인풋창에 ref 속성을 입력해준후, 렌더링 될때 idRef 를 출력하도록 했다.

ref.current 안에 input 값 그대로 담긴걸 볼 수 있다.

import { useEffect } from "react";
import { useRef } from "react";

function App() {
  const idRef = useRef();

  useEffect(() => {
    idRef.current.focus();
  },[]);

  return (
    <>
      <input ref={idRef} type={"text"} placeholder="아이디"></input>
      <button>로그인</button>
    </>
  );
}

export default App;

위처럼 focus 메서드를 사용해서 렌더링 될때 input 창에 포커스가 가도록 하였다.

profile
https://brgndy.me/ 로 옮기는 중입니다 :)

0개의 댓글