이롭게 현명하게

[React] 리액트 useRef로 특정 DOM 선택하기 / 리액트 DOM 접근하기 본문

웹 개발/React

[React] 리액트 useRef로 특정 DOM 선택하기 / 리액트 DOM 접근하기

dev_y.h 2023. 12. 28. 18:53
728x90
반응형

※ 본 포스팅은 윈도우11 환경에서 패스트 캠퍼스 강의를 수강하며 정리한 내용입니다.

 


 

목차

 

useRef란?

import

예시 코드

 


 


자바스크립트에서 특정 DOM을 선택해야 할 때 getElementById, querySelector 같은 DOM Selector 함수를 사용해 DOM을 선택했다.

리액트를 사용하는 프로젝트에서도 가끔 DOM을 직접 선택해야 할 때가 있다.

특정 element의 크기를 가져와야 한다든지, 스크롤바 위치를 가져오거나 설정해야 할 때, 또는 포커스를 설정할 때 등 다양한 상황이 따른다.

HTML5 Video 관련 라이브러리(video.js, JWPlayer) 또는 그래프 관련 라이브러리(D3, chart.js) 등 외부 라이브러리를 사용해야 할 때도 특정 DOM에다 적용하기 때문에 DOM을 선택해야 하는 상황이 발생할 수 있다.

그럴 때, 리액트에서 ref라는 것을 사용한다.


[useRef란?]

useRef : 저장공간(변수 관리) 또는 DOM 요소에 접근하기 위해 사용되는 React Hook이다.

여기서 Ref는 reference로 참조를 뜻한다.

개발하다 보면 DOM을 직접 선택해서 focus를 주거나 특정 Element의 크기나 색상을 변경하는 경우가 있는데 그때 사용하는 것이다.

.current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환한다.

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

더보기

DOM 이란?

HTML과 자바스크립트를 이어주는 공간으로 작성한 HTML을 자바스크립트가 이해할 수 있도록 object로 변환하는 것이다.

 

<useRef를 통해 관리되는 변수가 사용되는 곳>

  • setTimeout,setInterval을 통해 만들어진 id
  • scroll의 위치
  • 배열에 새 항목이 추가 될 때 필요한 고유 key 값
  • 외부 라이브러리를 사용하여 생성된 인스턴스

 

<특징>

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

  1. 컴포넌트가 계속해서 렌더링이 되어도 컴포넌트가 언마운드 되기 전까지는 값을 그대로 유지할 수 있다.
  2. current 속성은 값을 변경해도 상태를 변경할 때 처럼 리액트 컴포넌트가 리렌더링 되지 않는다.

렌더링과 상관없이 마운트된 시점부터 언마운트된 시점까지 값을 유지한다.

 

1. DOM 요소에 접근

useRef를 사용하면 손쉽게 input에 접근할 수 있다.

자바스크립트 getElementByid,querySelector와 비슷하다.

2. 저장공간(변수 관리)

ref는 state와 비슷하게 어떤 값을 저장하는 저장공간으로 사용된다.

컴포넌트 안에서 조회 및 수정할 수 있는 변수를 관리한다.

useRef로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링 되지 않는다.

리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그다음 렌더링 이후 업데이트된 상태를 조회할 수 있지만 useRef로관리하는 변수는 설정 후 바로 조회할 수 있다.

State의 변화 → 렌더링 → 컴포넌트 내부 변수들 초기화

Ref의 변화 → No 렌더링 → 변수들의 값이 유지

State의 변화 → 렌더링 → Ref의 값은 유지

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

변화는 감지해야 하지만, 그 변화가 렌더링을 발생시키면 안 될 때 사용한다.

 

더보기

함수형 컴포넌트에서 ref를 사용할 때는 useRef라는 Hook 함수를 사용한다.

클래스형 컴포넌트에서는 콜백 함수를 사용하거나 React.createRef라는 함수를 사용한다.

 

<장점>

자주 변경되는 값을 state로 관리하면 변경될 때마다 리렌더링이 일어나 성능이 저하된다.

하지만 useRef를 사용하면 값이 변경될 때마다 렌더링이 일어나지 않아 성능이 향상된다.

state : 값이 변경될 때마다 리렌더링이 일어난다.

ref : 값이 변경되어도 렌더링이 일어나지 않는다.

ref는 렌더링 이후에도 값이 유지되지만, 변수는 초기화된다.

 

<일반 변수와의 차이점>

state는 변경될 때마다 리렌더링이 일어나고 ref는 변경이 되어도 렌더링이 일어나지 않는다

ref의 값은 컴포넌트의 전생애주기를 통해서 관리되기 때문에 아무리 컴포넌트가 렌더링 되더라도 언마운트가 되기 전까지는 값을 계속해서 유지한다.

ref는 렌더링 이후에도 값이 유지되지만, 변수는 초기화된다.


[import]

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

 

<생성>

const 변수명 = useRef(초기값)

useRef()를 사용하여 Ref 객체를 만들고 이 객체를 선택하고 싶은 DOM에 ref 값으로 설정해 줘야 한다.

그러면 Ref 객체의 .current 값은 우리가 원하는 DOM을 가리키게 된다.

current라는 키값을 지닌 프로퍼티가 생성되고 값에 어떤 변경을 줄 때도 이 current를 이용한다.

<반환 요소 접근>

<input ref={변수명}/>

 

 


[예시 코드 ]

<1 DOM 요소 접근>

onReset 함수에서 input에 포커스를 하는 focus() DOM API를 호출하였다.

초기화 버튼을 클릭하면 이름 input에 포커스 된다.

// InputSample.js
import React,{useState,useRef}  from "react";

function InputSample(){
    const [inputs,setInputs] = useState({
        name:'',
        nickname:''
    });
    const nameInput = useRef();//nameInput이라는 객체가 만들어진다.
    // 선택하고 싶은DOM에 ref={nameInput}을 넣어준다.
    const {name,nickname} = inputs;

    const onChange = (e)=>{
        
        const {name,value} = e.target;

        setInputs({
            ...inputs,
            [name] : value
        });
    };

    const onReset = ()=>{
        setInputs({
            name:'',
            nickname:''
        })
        nameInput.current.focus(); // 초기화했을때 포커스가 잡힌다.
        //current : DOM을 가리킨다.
    }
    return(
        <div>
            <input name="name" placeholder="이름" onChange={onChange} value={name} ref={nameInput}/>
            
            <input name="nickname" placeholder="닉네임" onChange={onChange} value={nickname}/>
            <button onClick={onReset}>초기화</button>
            <div>
                <b>값: </b>
                {name}({nickname})
            </div>
        </div>
    );
}

export default InputSample;

 

 

 

<2저장공간(변수관리)>

기존 배열에 새 항목을 추가할 때 새 항목에서 사용할 고유 id를 관리한다.

 

UserList 컴포넌트 내부에서 배열을 직접 선언해서 사용하고 있는데 UserList에서 선언해 사용하는 대신 이 배열을 App에서 선언하고 UserList에게 props로 전달해 주었다.

// UserList.js //
import React from "react";

function User({user}){//props로 user를 받아온다.
    return(
        <div>
            <b>{user.username}</b> <span>{user.email}</span>
        </div>
    );

}

function UserList({users}){
    return(
        <div>
            {
                users.map(
                    user =>(<User user={user} key={user.id}/>)
                )
            }
        </div>
        
    );
    
}

export default UserList;
import React,{useRef} from "react";
import UserList from "./UserList";

function App() {
  const users =[
    {
        id : 1,
        username : 'uni',
        email : 'uni@gmail.com'
    },
    {
        id : 2,
        username : 'dog',
        email : 'dog@gmail.com'
    },
    {
        id : 3,
        username : 'cat',
        email : 'cat@gmail.com'
    }
];
  const nextId = useRef(4); // users배열에 3개의 항목이 등록되어있다.
                            // 마지막 항목이 3이므로 다음 항목인 4를 추가
  const onCreate = () =>{
    
    console.log(nextId.current)//만약 nextId에 담아둔 4라는 값을 조회하고 싶다면 
    // onCreate가 호출될 때 4가 출력된다.

    //nextId의 값을 변경할 때
    nextId.current +=1; // onCreate함수가 실행될 때 마다 nextId current를 사용하고
    // 사용한 다음에는 기존 값에 1을 더한다.
    // nextId 값은 5가 된다.
    
  }
  return (
    <div>
      <UserList users={users}/>
      {/*users배열을 userList에게 전달해준다. */}
    </div>

  );
}

export default App;

App.js에서 useRef()를 사용하여 nextId 변수를 만들었다.

useRef()를 사용할 때 파라미터를 넣어주면 이 값이 .current의 기본값이 된다.

이 값을 수정할 때는 .current 값을 수정하면 되고 조회할 때는 .current를 조회하면 된다.

 

nextId를 useRef로 관리한 이유 : nextId 값이 바뀐다고 해서 컴포넌트가 리렌더링 될 필요는 없다.

이 값을 useState로 관리해도 상관없다.

리렌더링 되는 값은 아니기 때문에 변수로 관리하는 것도 괜찮다.

useRef는 특정 DOM을 선택하고 싶을 때 쓸 수도 있지만 어떠한 변수를 계속 기억하고 싶을 때 이 값은 컴포넌트가 리렌더링 되도 계속 기억된다.

컴포넌트가 리렌더링 되도 4라는 값이고 nextId.current라는 값을 바꾸게 된다면 useRef(4)의 값도 바뀌게 된다.

값이 바뀐다고 해서 컴포넌트가 리렌더링 되지는 않는다.

 

 

<정리>

  • 자바스크립트에서 특정 DOM을 선택하는 역할 ex) getElementById, querySelector
  • 특정 DOM에 접근할 때 사용(ref 속성 사용)
  • 외부 라이브러리 사용할 때 유용
  • 원하는 위치에 ref={}의 형태로 작성
  • 포커스를 잡으려면 변수명.current.focus() 형태로 작성
  • 가리키는DOM변수명.current.이벤트함수
  • useRef는 .current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환한다.
  • 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지될 것이다.
  • 변화는 감지하지만 렌더링은 발생하지 않는다.→ 성능향상(state는 변화 시, 리렌더링 된다.)

 

 

 


잘못된 정보는 댓글에 남겨주시면 감사하겠습니다!😊

댓글과 좋아요는 큰 힘이 됩니다!

 

더보기

 

728x90
반응형
Comments