[React] useRef 사용법

언지·2024년 12월 28일

React

목록 보기
12/13
post-thumbnail

📍 useRef란?

새로운 Reference 객체를 생성하는 기능이다.

const refObject = useRef()
refObject : 생성한 레퍼런스 객체는 컴퍼넌트 내부의 변수로써 일반적인 값들을 저장할 수 있다.
❗️ useState와 동일한가?
: 아니요! 컴포넌트 내부의 변수로 활용한다는 점을 똑같지만 useState는 값이 변경되면 컴포넌트가 리렌더링되지만 useRef는 어떤 경우에도 리렌더링되지않아요!

그래서 렌더링에 영향을 미치고 싶지않은 그러한 변수를 생성할 때 useRef를 사용하면 된다.
또한 useRef를 이용하면 컴포넌트가 렌더링하는 특정 DOM 요소에 접근할 수 있다. ( + 해당 요소 조작까지 가능)

Ex) 특정 요소에 포커를 준다, 해당 요소의 스타일을 갑자기 변경시킨다. 등을 구현할 수 있음

위의 내용을 이해하려면 직접 예시를 만들어봐야할 것 같다.


📚 실습해보기

📍 선언하기

먼저 useRef를 선언해야한다.

Register.jsx

import { useRef } from "react";

📍 생성하기

Register.jsx

const refObj = useRef();
  • 초기값을 설정할 수 있음

refObj를 콘솔에 찍어보면

  • 레퍼런스 객체란 Current라는 Property에 현재 보관할 값을 담아두기만하는 단순한 자바스크립트 객체이다.
  • 레퍼런스 객체의 값을 사용하려면 refObj.current라고 적으면 된다.

📍 useRef 버튼 만들기

Register.jsx(초기값 0으로 설정)

const refObj = useRef(0);
 console.log(refObj);

Register.jsx (return 문 안에 작성)

{/* useRef 사용해보기 */}
<button
	onClick={() => {
	refObj.current++;
	console.log(refObj.current);
}}>
	ref +1
</button>

💡 값을 출력하긴하지만 리렌더링을 유발시키지는 않는다.
그러면 onClick 핸들러만 계속 실행된다.
또한 console.log(refObj); 해당 콘솔 로그도 새로고침했을 때만 출력되고 버튼을 클릭했을 때 다시 출력되지않는다.

레퍼런스 객체는 우리 컴포넌트 내부에서 렌더링에 영향을 미치지않아야하는 그런 변수를 생성할 때 활용


🔄 사용자가 수정하는 횟수를 useRef를 사용하여 카운트하기

Register.jsx(초기값 0으로 설정)

const counrRef = useRef(0);

const onChange = (e) =>{
	counrRef.current++;				➡️ 변경할때마다 0인 current값 증가시키기
	console.log(counrRef.current);	➡️ counrRef 객체의 값을 로그로 출력하기
	setInput({
		...input,
		[e.target.name] : e.target.value,
	})
}

🛠️ DOM 요소들을 직접 조작해보기

Register.jsx (return 문 안에 작성)

<button onClick={onsubmit}>제출</button>

onsubmit 함수를 만들어야겠지?

Register.jsx

const inputRef = useRef();	➡️ 레퍼런스 객체 생성해주고

const onsubmit = () =>{
	// 이름을 정확히 입력했는지 확인
	if(input.name === ""){
		// 이름을 입력하는 DOM 요소에 포커스
		console.log(inputRef.current);
		inputRef.current.focus();
	}
}

이름이 비어져있을 경우 해당 input 태그에 포커스가 가게끔 동작한다.
근데 폼에는 수많은 input 태그가 있는데 특정 input 태그라는 걸 알려면
input 태그 안에 ref 속성을 넣어주고 속성값으로 {inputRef} 을 넣어주면 된다.

inputRef.current 에는 해당 DOM 요소가 출력된다.


🧐 굳이 useRef를 사용해야하는가?

import { useState, useRef } from "react";

// 간단한 회원가입 폼 만들기
// 1. 사용자의 이름 -> 사용자가 입력하는 이름을 State 로 보관
// 2. 생년월일
// 3. 국적
// 4. 자기소개

const Register = () =>{

    const [input, setInput] = useState({
        name:"",
        birth:"",
        country:"",
        bio:""
    })

    const counrRef = useRef(0);
    // const inputRef = useRef();

    let count = 0;

    const onChange = (e) =>{
        // counrRef.current++;
        // console.log(counrRef.current);
        count++;
        console.log(count);
        setInput({
            ...input,
            [e.target.name] : e.target.value,
        })
    }

    const onsubmit = () =>{
        // 이름을 정확히 입력했는지 확인
        if(input.name === ""){
            // 이름을 입력하는 DOM 요소에 포커스
            console.log(inputRef.current);
            inputRef.current.focus();
        }
    }

    return (
        <div>
            {/* 이름 */}
            <div>
                <input
                ref={inputRef}
                name="name"
                value={input.name} 
                onChange={onChange} 
                placeholder={"이름"}/>
            </div>
            
            {/* 생년월일 */}
            <div>
                <input 
                name="birth"
                type="date" 
                value={input.birth} 
                onChange={onChange}/> 
            </div>

            {/* 국적 */}
            <div>
                <select 
                name="country"
                value={input.country} 
                onChange={onChange}>
                    <option>-</option>
                    <option>한국</option>
                    <option>미국</option>
                    <option>영국</option>
                </select>
            </div>

            {/* 자기소개 */}
            <div>
                <textarea 
                name="bio"
                value={input.bio} 
                onChange={onChange}/>
            </div>

            <button onClick={onsubmit}>제출</button>
        </div>
    )
};

export default Register;

let count = 0;으로 만들어서 사용하면 안되나?
위의 코드를 let로 변수 선언하여 바꿔봤을 때 console.log(count) 하면 1 밖에 출력이 안된다.
➡️ 왜냐하면 OnChangeEvent 핸들러가 실행되면서 스테이트 값을 변경하는데 그러면 Register 컴포넌트가 리렌더링되면서 count가 0이되기 때문이다.

useRef나 useState를 이용해서 만든 리액트의 특수한 변수들은 컴퍼넌트가 리렌더링 된다고 해도 다시 리셋되지않는다.
➡️ 애초에 그렇게 설계되어있음


컴퍼넌트 내부의 변수가 필요하다면

렌더링에 영향을 주는 useState나

렌더링에 영향을 주지않는 useRef를 사용하면 된다.

0개의 댓글