본문 바로가기

나야, 리액트 스터디

[week 6] Ref로 값 참조하기, Ref로 DOM조작하기

 

안녕하세요 ~ YB 김가현입니다 😴

이번주는 Ref로 값 참조하기, Ref로 DOM조작하기 파트에 대해 알아보겠습니다

useRef 훅에 대해서 잘 몰랐기 때문에 …. 새로운 내용들을 한가득 접했던 한 주였어요 !!

😲 시작해보겠습니다 ~

 


useRef ?

  • DOM 노드나 다른 React 요소에 대한 참조를 만들 때 사용하는 훅

사용하기

import { useRef } from 'react';
const ref = useRef(0);

 

useRef를 import 하고, 호출하여 참조할 초깃값을 인자로 전달한다 (타입 상관 x)

이 ref는 모든 DOM 요소에 접근할 수 있게 된다.

 

위의 useRef는 다음과 같은 객체를 반환한다.

{
  current: 0 // useRef에 전달한 값 
}

 

current는 useRef가 반환하는 객체에 내장된 기본 속성인데, 항상 위와 같은 형태의 mutable한 객체를 반환한다. 우리는 이 current 속성을 통해 값을 읽거나 수정할 수 있다.

useRef의 특징

1. 내부 값의 변경사항을 감지하지 못하기 때문에 리렌더링이 발생하지 않는다.

const ref = useRef(0)

 

useRef 가 반환한 객체 ref는 참조형 데이터로, 메모리 상의 주소값(참조)를 가리킨다.

ref.current의 값을 바꿔도 객체의 주소값 자체는 변하지 않으므로, React는 이를 변경사항으로 인식하지 않는다. 따라서 리렌더링이 발생하지 않는다.

만약 useRef 값의 변경에 따라 특정 로직을 수행하고 싶다면 ref 대신 상태값을 사용하거나, useEffect의 의존성 배열에서 해당 ref를 참조할 수 있게 해야 한다.

 

2. 반환된 useRef 객체는 컴포넌트의 전 생애주기를 통해 유지 된다.

따라서 컴포넌트가 계속해서 렌더링 되어도 컴포넌트가 언마운트 되기 전까지는 값을 그대로 유지할 수 있다.

 

useRef 내부 뜯어보기

// Inside of React
function useRef(initialValue) {
  const [ref, unused] = useState({ current: initialValue });
  return ref;
}

 

ㅇㅓ라랏 ~ useState ..? 내부 코드를 보면 알겠지만, useState를 약간 변형한 형태이다.

차이점이라 한다면, setter 함수를 반환하지 않는다. 리렌더링을 트리거 할 필요가 없기 때문이다.

 

더 자세히 알고 싶다면 . .  아래 글 읽어보기 !

 

useRef의 내부 동작 원리

useRef의 내부 동작 원리

velog.io

 

최초 렌더링부터 어떻게 ref가 연결되고 분리되는지, 변경을 확인하는지 설명하고 있다.

 

useRef는 언제 사용하는 것일까 ?

 

1. 저장공간

값이 변경되더라도, 렌더링은 발생시키지 않아야 하는 값을 다룰 때 유용하게 사용할 수 있다. useRef는 ref 안에 값이 변경되더라도 컴포넌트가 리렌더링 되지 않기 때문이다.

 

useState도 useRef와 비슷하게 변경 가능한 상태값을 저장한다는 공통점이 있다 ! 그럼 useState와의 차이점은 ..?

  • useRef는 반환값인 객체 내부에 있는 current로 값에 접근 또는 변경할 수 있다.
  • useRef는 그 값이 변하더라도 렌더링을 발생시키지 않는다.

 

refs vs state (by 공식문서)

 

😦 흠 .... 함수 밖에서 변수를 선언하여 관리해도 되는 것 아닌가요 ?

함수 밖에 변수를 선언하여 데이터를 관리하는 것도 가능하다 !

컴포넌트의 렌더링과 무관하게 값을 유지할 수 있지만, 컴포넌트가 실행되기 전부터 value값이 기본적으로 존재하기 때문에 불필요하게 메모리를 차지하고 있는 문제점이 발생한다.

또한 이 경우에는 모든 컴포넌트가 해당 변수를 공유하게 되기 때문에, 의도치 않은 충돌의 위험성 역시 존재한다.

 

 

2. DOM 요소에 접근

ref를 통해 돔 요소에 접근할 수 있다. (Vanilla JS의 Document.querySelector()와 같은 너낌 ~)

아래와 같은 경우에 유용하게 사용할 수 있다.

  • 특정 엘리먼트의 크기나 위치를 알아야 할 때
  • 스크롤 바의 위치를 다룰 때
  • input 요소를 클릭하지 않아도 포커스를 주고 싶을 때

useRef가 반환하는 객체를 접근하고자 하는 요소 태그의 ref 속성에 바인딩하여 사용할 수 있다.

import { useRef } from 'react';
const ref = useRef(value)

<input ref={ref}/>

 

 

useRef로 DOM 요소에 접근해보자 !

import { useRef } from 'react';

function MyInput(props) {
  return <input {...props} />;
}

export default function MyForm() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <MyInput ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}

 

문제가 없는 코드라면, Focus the input 이라는 버튼을 클릭했을 때 MyInput이 focus 되어야 한다. 그러나 버튼을 클릭해도, focus 되지 않는다.

😵‍💫 ref로 잘 전달 했는데요 ……?

 

→ ref는 함수형 컴포넌트에서 자동으로 전달되지 않기 때문이다. 따라서 일반적인 props를 넘겨주는 방식은 사용할 수 없다.

그 래 서 .. 자식 컴포넌트에서 ref를 props로 받기 위해서는 forwardRef를 사용해야 한다.

const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

 

forwardRef는 함수형 컴포넌트를 감싸면서, 두 번째 매개변수로 부모로부터 전달된 ref를 받을 수 있게 해준다.

MyInput은 전달받은 ref를 input 요소에 바인딩한다.

 

++) React 19 버전 이후로는 forwardRef를 사용하지 않아도 자식 컴포넌트에서 ref를 전달 받을 수 있다고 한다 ~! 참고하기

 

 

ref를 남용하지 마세요

공식문서에서 ref를 사용한 명령형 코드는 꼭 필요한 경우를 제외하고 남용하지 말라고 말하고 있다. 

React의 장점인 선언형 프로그래밍 원칙과 배치되기 때문에, 조심해서 사용해야 한다고 하네요 ! React의 설계 원리와도 어긋나는 부분이 있는 것 같고용 ~ 

 

 

 


 

 

'나야, 리액트 스터디' 카테고리의 다른 글

[week 6] useRef 뿌시기  (3) 2024.12.01
[week6] Ref  (1) 2024.12.01
[week6] Ref로 값 참조하기  (3) 2024.12.01
[week5] state 관리하기  (2) 2024.11.25
[week5] 컴포넌트 간 state 공유  (4) 2024.11.25