기술/React

[React] useRef - 리액트에서 DOM 조작하기

leedaramji 2024. 2. 27. 00:32

useRef

 

리액트에서 Ref를 이용하면 돔(DOM) 요소들을 직접 조작할 수 있다. Ref는 Ref-erence의 줄임말로 참조라는 뜻이다.

 

💡

// useRef 불러오기
const ref = useRef(value)
// ref 안의 current에 저장
{ current: value }
// 수정 (ref에 접근)
ref.current = "hello"
{ current: "hello" }
// 속성으로 넣어주면 해당 요소에 접근 가능
const ref = useRef(value)
<input ref={ref} /> 📌

 

  • 함수형 컴포넌에서 useRef를 부르면 ref 오브젝트를 반환해준다.
  • 인자로 넣어준 초깃값은 ref 안의 current에 저장된다.
  • current는 언제든지 원하는 값으로 수정 가능하다.
  • 반환된 ref는 컴포넌트의 전 생애주기를 통해 유지된다.
    • 컴포넌트가 계속 렌더링 되어도 컴포넌트가 unmount 되기 전까지 값 유지 가능

 


 

🌏 언제 사용될까?

 

1) 저장 공간

  • state와 비슷하게 어떠한 값을 저장해 두는 저장공간
  • 함수형 컴포넌트는 말 그대로 함수다. 리렌더링이 되면 함수가 다시 불려지는 거기 때문에 내부에 있는 모든 변수 들이 전부 초기화 된다. 그렇기 때문에 원하지 않는 렌더링 때문에 곤란해진다.
    • State의 변화 -> 렌더링 -> 컴포넌트 내부 변수들 초기화
  • state 대신 ref안에 값을 저장하면 어떤 장점이 있을까?
    • 값을 아무리 변경해도 다시 렌더링되지 않는다. 불필요한 렌더링 발생하지 않는다.
    • Ref의 변화 -> No 렌더링 -> 변수의 값이 유지됨 ✨
    • State의 변화 -> 렌더링 -> 그래도 Ref 의 값은 유지됨
  • 변경시 렌더링을 발생시키지 말아야 하는 값을 다룰 때 편리하다.

 

📌
리액트에서 State가 변경된다는 것은 컴포넌트가 다시 렌더링된다는 뜻이다. 함수형 컴포넌트는 함수이기 때문에 함수가 다시 불려진다는 것이다. 즉, state가 변경될 때마다 함수 컴포넌트가 다시 불리기 때문에 화면이 계속 새로 렌더링 된다.

 

2) DOM 요소에 접근

  • input 요소에 클릭하지 않아도 focus()를 줄 때

 

📌
엄청 자주 바뀌는 값을 state에 넣어서 사용한다면? 값이 바뀔 때마다 계속 렌더링 되기 때문에 성능에 좋은 영향을 미친다. ref를 사용하면 아무리 바뀌어도 렌더링을 발생 시키지 않기 때문에 성능에 좋다. 그리고 레더링 이후에도 값을 계속 유지한다.

= useRef는 변화는 감지해야 하지만 그 변화가 레더링을 발생시키면 안되는 값을 다룰 때 편리

 


 

🌏 Ref와 변수의 차이

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

const App = () => {
    const [renderer, setRenderer] = useState(0);
    const countRef = useRef(0);	📌 브라우저에 mounting 된 시점부터 해제되는 순간까지 같은 값을 유지
    let countVar = 0;	📌 변수는 화면이 렌더링 되면 처음 값으로 돌아간다
    
    const doRendering = () => {
    	setRenderer(renderer + 1); 📌 state 값이 바뀌면 화면이 새로 렌더링
    };
    
    const increaseRef = () => {
    	coountRef.current = count.current + 1;
        console.log('ref: ', countRef.current);
    };
    
    const increaseVar = () => {
    	countVar = countVar + 1;
        console.log('var: ', countVar);
    };
    
    const printResults = () => {
    	console.log(`ref: ${countRef.current}, var: ${countVar}`);
    };
    
    return (
    	<div>
            <p>Ref: {countRef.current}</p>
            <p>Var: {countVar.current}</p>
            <button onClick={doRendering}>Render!</button> 📌 클릭하면 화면이 업데이트 된다.
            <button onClick={increaseRef}>Ref Up!</button> 📌 렌더링 이후에도 값 유지
            <button onClick={increaseVar}>Var Up!</button> 📌 렌더링 이후 값 초기화 됨
            <button onClick={printResults}>Ref Var 값 출력!</button> 📌 콘솔창에 값 출력해서 보여줌
        </div>
    );
};
export default Body;

 

  • 💡 렌더링 버튼을 클릭하면 ?
    • ref는 렌더링 이후에도 값 유지
    • var는 초기화 됨

 

 


 

🌏 [useRef 사용하기]

 

리액트에서는 useRef라는 리액트 함수를 이용해 Ref 객체를 생성한다. 

 

📌[초기화 하기]

import { useRef, useState } from "react";

function Body() {
    const [text, setText ] = useState("");
    const textRef = useRef();📌 1
    
    const handleOnchange = (e) => {
    	setText(e.target.value);
    };
    
    const handleOnClick = (e) => {
    	alert(text);
        textRef.current.value = ""; 📌2
    };
    
    return (
    	<div>
        <input ref={textRef} value={text) onChange={handleOnChange} /> 📌3
            <button onClick={handleOnClick}>작성 완료></input>
        </div>
    );
}
export default Body;

 

  1. 함수 useRef는 인수로 전달한 값을 초깃값으로 하는 Ref 객체를 생성한다. 생성한 Ref를 상수 textRef에 저장한다.
  2. 버튼을 클릭하면 이벤트 핸들러 handleOnClick이 실행된다. 대화 상자에 <확인> 버튼을 클릭하면, textRef.current의 value 값을 공백 문자열로 초기화 된다.
  3. <input> 태그에서 ref={textRef} 명령으로 textRef가 돔 입력 폼에 접근하도록 설정한다. 이제 textRef를 이용하면 입력 폼을 직접 조작할 수 있다.

 

* textRef.current = textRef가 현재 참조하고 있는 돔 요소

 

 

📌[포커스 하기]

 

웹 서비스에서는 사용자가 특정 폼에 내용을 입력하지 않거나 내용이 정한 길이보다 짧으면 해당 폼을 포커스하여 사용자의 추가 입력을 유도한다. 리액트의 Ref 기능을 이용하면 특정 요소에 포커스 기능을 지정할 수 있다.

 

import { useRef, useState } from "react";

function Body() {
    const [text, setText ] = useState("");
    const textRef = useRef();
    
    const handleOnchange = (e) => {
    	setText(e.target.value);
    };
    
    const handleOnClick = (e) => {
    	if (text.length < 5) {
        	textRef.current.focus(); 📌 1
        } else {
        	alert(text);
            setText(""); 📌 2
        }
    };
    
    return (
    	<div>
        <input ref={textRef} value={text) onChange={handleOnChange} />
            <button onClick={handleOnClick}>작성 완료></input>
        </div>
    );
}
export default Body;

 

  1. 현재 <input> 태그로 지정한 폼에 입력한 텍스트가 다섯 글자보다 적다면 textRef.current가 참조하는 입력 폼에 포커스를 실행한다. focus()는 현재 돔 요소에 포커스를 지정하는 메서드이다.
  2. 텍스트 폼에 입력한 값을 초기화하기 위해 set 함수 setText를 호출하고 인수로 빈 문자열을 전달한다. Ref를 사용하지 않고도 set 함수로 입력 폼을 초기화할 수 있다.

 

 

import React, { useEffect, useRef } from 'react';

const App = () => {
    const inputRef = useRef(); 📌
    
    useEffect(() => {	📌 useEffect를 넣어서 맨 처음 렌더링될 때만 실행되게 만들어 준다.
    	inputRef.current.focus(); 📌 ref에 접근해서 focus() 해준다.
    }, []);
    
    const login = () => {
    	alert('환영합니다. ${inputRef.current.value}!!🩷); 
        inputRef.current.focus(); 📌 로그인 알림 확인을 하면 input에 focus() 해준다.
    };
    
    return (
    	<div>
        	<input ref={inputRef} type="text" placeholder="username" /> 📌input에 대한 ref 참조
            <button onClick={login}>로그인</button>
        </div>     
    );
};
export default Body;

 

 

 

📕참고: 한 입에 잘라 먹는 리액트 - 이정환

📕참고: useRef -유튜브 별코딩

'기술 > React' 카테고리의 다른 글

[React] 컴포넌트  (0) 2024.02.27
[React] 리액트의 데이터 흐름  (0) 2024.02.27
[React] useState - 컴포넌트와 상태  (0) 2024.02.27
[React] Props - 컴포넌트에 값 전달하기  (0) 2024.02.27
[React] JSX  (0) 2024.02.27