useRef를 한 문장으로 설명하자면 리랜더링을 필요로 하지 않는 값을 참조(reference) 할 때 사용하는 리액트 내장훅이다.
침조 대상은 primitive 값(number, string...) 부터 DOM까지 광범위하며 참조값은 useRef(값).current값에 저장할 수 있다.
DOM요소를 참조하려면 JSX의 속성(attribute)에서 ref를 연결하면 된다.
console.log(useRef(1)); // {current: 1}
console.log(useRef("a")); // {current: "a"}
console.log(useRef(true)); // {current: true}
// JSX
import { useRef } from 'react';
export default function App() {
const idRef = useRef<HTMLInputElement | null>(null);
console.log(idRef.current) // <input type="text" id="id" name="id">
return (
<input type="text" id="id" name="id" ref={idRef} />
);
}
리랜더링이 필요한 값은 useState, state값이 변하면 컴포넌트가 리랜더링된다.
리랜더링이 필요없는 값은 useRef, ref값이 변해도 컴포넌트가 리랜더링되지 않는다.
뭔소리인지 잘 와닿지 않으므로 퀴즈들과 예시를 보면서 useState와 useRef에 차이점에 대해서 알아보자!
import { useState } from 'react';
export default function App() {
const [stateCount, setStateCount] = useState(0);
const handleClick = () => {
setStateCount(stateCount + 1);
console.log('inside handleClick : ', stateCount);
};
console.log('outside handleClick : ', stateCount);
return (
<div className="text-center p-20 bg-red-50 h-screen">
<span>{stateCount}</span>
<button onClick={handleClick} className="bg-sky-200 w-10">
+
</button>
</div>
);
}
클릭 전

클릭 후

import { useRef } from 'react';
export default function App() {
const refCount = useRef(0);
const handleClick = () => {
refCount.current++;
console.log('inside handleClick : ', refCount.current);
};
console.log('outside handleClick : ', refCount.current);
return (
<div className="text-center p-20 bg-red-50 h-screen">
<span>{refCount.current}</span>
<button onClick={handleClick} className="bg-sky-200 w-10">
+
</button>
</div>
);
}
클릭 전

클릭 후

import { useRef, useState } from 'react';
export default function App() {
const [stateCount, setStateCount] = useState(0);
const refCount = useRef(0);
const handleClick = () => {
refCount.current++;
setStateCount(stateCount + 1);
console.log('inside handleClick state : ', stateCount);
console.log('inside handleClick ref : ', refCount.current);
};
console.log('outside handleClick state : ', stateCount);
console.log('outside handleClick ref : ', refCount.current);
return (
<div className="text-center p-20 bg-red-50 h-screen">
<span>{refCount.current}</span>
<button onClick={handleClick} className="bg-sky-200 w-10">
+
</button>
</div>
);
}
클릭 전

클릭 후

import { useRef, useState } from 'react';
export default function App() {
const [stateCount, setStateCount] = useState(0);
const refCount = useRef(0);
const handleClick = () => {
refCount.current++;
console.log('inside handleClick state : ', stateCount);
console.log('inside handleClick ref : ', refCount.current);
};
console.log('outside handleClick state : ', stateCount);
console.log('outside handleClick ref : ', refCount.current);
return (
<div className="text-center p-20 bg-red-50 h-screen">
<span>{refCount.current}</span>
<button onClick={handleClick} className="bg-sky-200 w-10">
+
</button>
</div>
);
}
클릭 전

클릭 후

import { useState } from 'react';
export default function App() {
const [signinInput, setSigninInput] = useState({
id: '',
password: '',
});
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setSigninInput((prev) => ({ ...prev, [name]: value }));
};
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log(signinInput); // {id: 'howooking', password: '1234'}
};
return (
<form
className="text-center p-20 bg-red-100 h-screen flex flex-col gap-2 items-center"
onSubmit={onSubmit}
>
<div>
<label htmlFor="id">아이디 : </label>
<input
id="id"
name="id"
value={signinInput.id}
onChange={handleChange}
/>
</div>
<div>
<label htmlFor="password">비밀번호 : </label>
<input
type="password"
id="password"
name="password"
value={signinInput.password}
onChange={handleChange}
/>
</div>
<button className="bg-sky-100 w-60">로그인</button>
</form>
);
}

import { useRef } from 'react';
export default function App() {
const idRef = useRef<HTMLInputElement | null>(null);
const passwordRef = useRef<HTMLInputElement | null>(null);
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const signinInput = {
id: idRef.current?.value,
password: passwordRef.current?.value,
};
console.log(signinInput); // {id: 'howooking', password: '1234'}
};
return (
<form
className="text-center p-20 bg-red-100 h-screen flex flex-col gap-2 items-center"
onSubmit={onSubmit}
>
<div>
<label htmlFor="id">아이디 : </label>
<input
id="id"
ref={idRef} />
</div>
<div>
<label htmlFor="password">비밀번호 : </label>
<input
type="password"
id="password"
ref={passwordRef}
/>
</div>
<button className="bg-sky-100 w-60">로그인</button>
</form>
);
}