[React] ๋ฆฌ์กํธ Hooks (3) - useRef: ๋ณ์ ๊ด๋ฆฌ
๐ useRef๋?
ํจ์ํ ์ปดํฌ๋ํธ์์ useRef๋ฅผ ํธ์ถํ๋ฉด ref Object๋ฅผ ๋ฐํํฉ๋๋ค. ref Object์ ํํ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
{ current: value }
- ์ธ์๋ก ๋ฃ์ด์ค ์ด๊ธฐ๊ฐ์ด ์ ์ฅ์ด ๋ฉ๋๋ค.
- ์์ ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์ธ์ ๋ ์ํ๋ ๊ฐ์ผ๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅํฉ๋๋ค.
- ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง์ด ๋์ด๋ ์ธ๋ง์ดํธ ๋๊ธฐ ์ ๊น์ง๋ ๊ฐ์ ๊ณ์ ์ ์งํ ์ ์์ต๋๋ค.
๐ ์ธ์ useRef๋ฅผ ์ฌ์ฉํ๋์?
1. ref๋ state์ ๋น์ทํ๊ฒ ๊ฐ์ ์ ์ฅํด๋๋ ์ ์ฅ ๊ณต๊ฐ์ผ๋ก ์ฌ์ฉ์ด ๋ฉ๋๋ค.
state๊ฐ ๋ณ๊ฒฝ์ด ๋๋ฉด ๋ฆฌ๋ ๋๋ง์ด ๋๊ณ ํจ์๊ฐ ๋ค์ ํธ์ถ๋๊ธฐ ๋๋ฌธ์ ์ปดํฌ๋ํธ ๋ด๋ถ ๋ณ์๋ค์ ์ด๊ธฐํํฉ๋๋ค. ๊ทธ๋์ ์ํ์ง ์๋ ๋ ๋๋ง ๋๋ฌธ์ ๊ณค๋ํด์ง๋ ๊ฒฝ์ฐ๊ฐ ์๊น๋๋ค.
ref๊ฐ ๋ณํํด๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง์ด ๋์ง ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ณ์๋ค์ ๊ฐ์ด ์ ์ง๊ฐ ๋ฉ๋๋ค. ๋ง์ฝ state์ ๋ณํ๋ก ์ธํด ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง์ด ๋์ด๋ ref์ ๊ฐ์ ์ ์ง๊ฐ ๋ฉ๋๋ค.
2. ref๋ฅผ ํตํด DOM ์์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋ํ์ ์ผ๋ก input ์์๋ฅผ ํด๋ฆญํ์ง ์์๋ focus๋ฅผ ์ฃผ๊ณ ์ถ์ ๋ ์ฌ์ฉํฉ๋๋ค. ๋ก๊ทธ์ธ ํ๋ฉด์ด ๋ณด์ฌ์ก์ ๋, ์๋์ ์ผ๋ก ํฌ์ปค์ค๊ฐ ๋๊ฒ๋ ๋ง๋ค ์ ์์ต๋๋ค. ์ด๋ฐ ๊ธฐ๋ฅ์ javascript์ Document.querySelector()์ ๋น์ทํ ๊ธฐ๋ฅ์ ํฉ๋๋ค.
๐ ref.current
๋จผ์ ํ์ฌ state(count) ๊ฐ์ ๋ณด์ฌ์ฃผ๋ฉด์ ๋ฒํผ์ ํด๋ฆญ์ setState(setCount)๋ฅผ ์ด์ฉํด state ๊ฐ์ 1์ฉ ์ฆ๊ฐ์ํค๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
const App = () => {
const [count, setCount] = useState(0);
const increaseCountState = () => {
setCount(count + 1);
};
return (
<div>
<h1>State: {count}</h1>
<button onClick={() => increaseCountState()}>State +1</button>
</div>
);
};
export default App;
๋ฒํผ์ ๋๋ ์ ๋ state ๊ฐ์ด ๋ณํํ๋ ๊ฒ์ ๋ฐ๋ก ๋ณผ ์ ์๋ ์ด์ ๋ ์ปดํฌ๋ํธ๊ฐ ๊ณ์ ๋ ๋๋ง์ด ๋๊ธฐ ๋๋ฌธ์ ๋๋ค.
์ด์ useRef๋ฅผ ์ฌ์ฉํด๋ณด๊ฒ ์ต๋๋ค.
const countRef = useRef(0);
console.log(countRef);
ํด๋น ์ฝ๋๋ฅผ App ์ปดํฌ๋ํธ ์์ ๋ฃ์ด ์ฝ์์ ํ์ธํด๋ณด๊ฒ ์ต๋๋ค.
countRef๋ current๋ผ๋ ๊ฐ์ ๊ฐ์ง๋ฉฐ current ์์์๋ ์ฒ์์ ์ค์ ํด๋ 0์ด๋ผ๋ ์ด๊ธฐ๊ฐ์ ํ์ธํ ์ ์์ต๋๋ค.
countRef.current๋ก ์ด ๊ฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค. state๋ฅผ ํ์ฉํ ๋ฐฉ์ ๊ทธ๋๋ก ํ๋จ์ ref ๊ฐ์ 1์ฉ ์ถ๊ฐํ๋ ๋ฒํผ์ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
import React, { useEffect, useState, useRef } from "react";
import "./App.css";
const App = () => {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const increaseCountState = () => {
setCount(count + 1);
console.log("State: ", count + 1);
};
const increaseCountRef = () => {
countRef.current += 1;
console.log("Ref: ", countRef.current);
};
return (
<div>
<h1>State: {count}</h1>
<h1>Ref: {countRef.current}</h1>
<button onClick={() => increaseCountState()}>State +1 </button> // ๋ ๋๋ง์ด ๋ฉ๋๋ค.
<button onClick={() => increaseCountRef()}>Ref +1</button> // ๋ ๋๋ง์ด ๋์ง ์์ต๋๋ค.
</div>
);
};
export default App;
Ref + 1 ๋ฒํผ์ ์๋ฌด๋ฆฌ ๋๋ฌ๋ ํ๋ฉด์ ์ซ์๊ฐ ๋์ด๋์ง ์์ง๋ง, State + 1 ๋ฒํผ์ ๋๋ฅด๋ฉด ํ๋ฉด์์ ์ซ์๊ฐ ref์ current ๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค. state๊ฐ ๋ณ๊ฒฝ์ด ๋์์ ๋ ์ปดํฌ๋ํธ๊ฐ ๋ค์ ๋ ๋๋ง ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ฆ, ์ ์ฒด ํ๋ฉด์ด ๋ค์ ๊ทธ๋ ค์ง๋๋ค.
๋งค์ฐ ์์ฃผ ๋ฐ๋๋ ๊ฐ์ state๋ก ๋ณด๊ดํ๋ค๋ฉด ์ด ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ๋ ๋๋ง์ด ๋ ๊ฒ์ ๋๋ค. ํ์ง๋ง ref์ ๋ณด๊ดํ๋ค๋ฉด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ๋ ๋๋ง์ด ๋์ง ์๊ธฐ ๋๋ฌธ์ ๋ ์ข์ ์ฑ๋ฅ์ ์ ์งํ ์ ์์ต๋๋ค.
๐ ref VS var
์ด๋ฒ์๋ ref์ var๋ฅผ ์ฌ๋ ค์ฃผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
const App = () => {
const countRef = useRef(0);
let countVar = 0;
const increaseRef = () => {
countRef.current += 1;
console.log("ref: ", countRef.current);
};
const increaseVar = () => {
countVar += 1;
console.log("var: ", countVar);
};
return (
<div>
<h1>Ref: {countRef.current}</h1>
<h1>Var: {countVar}</h1>
<button onClick={increaseRef}>Ref +</button>
<button onClick={increaseVar}>Var +</button>
</div>
);
};
export default App;
์ด๋ ๊ฒ ๋ฒํผ์ ํด๋ฆญํด๋ ref์ ๋ณ์ ๋ชจ๋ ๋ณ๊ฒฝ๋๋ ๊ฒ์ ๋ณผ ์ ์์ง๋ง, ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ์ง ์๊ธฐ ๋๋ฌธ์ ํ๋ฉด์์ ๋ณผ ์๋ ์์ต๋๋ค. ๊ทธ๋์ ๋ ๋๋ง์ ๋ด๋นํ๋ ๋ฒํผ์ ํ๋ ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
const App = () => {
const [renderer, setRenderer] = useState(0);
const countRef = useRef(0);
let countVar = 0;
const doRendering = () => {
setRenderer(renderer + 1);
};
const increaseRef = () => {
countRef.current += 1;
console.log("ref: ", countRef.current);
};
const increaseVar = () => {
countVar += 1;
console.log("var: ", countVar);
};
return (
<div>
<h1>Ref: {countRef.current}</h1>
<h1>Var: {countVar}</h1>
<button onClick={setRenderer}>๋ ๋๋ง</button>
<button onClick={increaseRef}>Ref +</button>
<button onClick={increaseVar}>Var +</button>
</div>
);
};
export default App;
ref์ var ๊ฐ์ ๋๋ฆฌ๋ ๋ฒํผ์ ๊ฐ๊ฐ ๋๋ฒ์ฉ ํด๋ฆญํ๊ณ ๋ ๋๋ง ๋ฒํผ์ ํด๋ฆญํ๋ฉด
Ref ๊ฐ๋ง ๋ค์ ๊ทธ๋ ค์ง๊ฒ ๋ฉ๋๋ค. Var์ ๊ฐ์ 0์ผ๋ก ๊ทธ๋๋ก์ ๋๋ค.
์ด์ ๋ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง์ด ๋๋ค๋ ๊ฒ = ์ปดํฌ๋ํธ๋ฅผ ๋ํ๋ด๋ ํจ์๋ฅผ ๋ค์ ํธ์ถ = ํจ์ ๋ด๋ถ์ ์๋ ๋ณ์๊ฐ ์ด๊ธฐํ
๋๊ธฐ ๋๋ฌธ์ ๋ณ์๋ ๊ณ์ ์ด๊ธฐํ๊ฐ ๋ฉ๋๋ค. ํ์ง๋ง, ref์ ๊ฐ์ ์์ ์ฃผ๊ธฐ(๋ง์ดํธ ์์ ๋ถํฐ ์ธ๋ง์ดํธ ์์ ๊น์ง)๋ฅผ ํตํด ์ ์ง๋๊ธฐ ๋๋ฌธ์ ๋ ๋ ์ด์ ์ ๊ฐ์ง๊ณ ์๋ ๊ฐ์์ ๋ณ๊ฒฝ์ด ๋ฉ๋๋ค. ๋ณ์๋ ๋ค์ 0๋ถํฐ ์์ํ๊ธฐ ๋๋ฌธ์ ๋ค์ ์ฒ์๋ถํฐ ๋ณ๊ฒฝ์ด ๋ฉ๋๋ค.
๐ useRef ๋ ๋๋งํ ๋ ํ์ฉํ๊ธฐ
๊ทธ๋ผ ์ด์ , count ๊ฐ์ 1์ฉ ์ฆ๊ฐ์์ผ์ฃผ๋ ์ปดํฌ๋ํธ๋ฅผ ๋ง๋ค๊ณ ํ๋จ์ ๋ ๋๋ง์ด ๋ ํ์๋ฅผ ๋ณด์ฌ์ฃผ๋๋ก ํ๊ฒ ์ต๋๋ค.
useEffect ์ฌ์ฉ?
์ ๊ทผ ๋ฐฉ์
1. useState๋ก renderCount๋ผ๋ ์๋ก์ด state๋ฅผ ๋ง๋ค๊ธฐ
2. useEffect๋ ๋งค๋ฒ ๋ ๋๋ง์ด ๋ ๋๋ง๋ค ์คํ๋๋ ํจ๊ป setRenderCount(renderCount +1) ์คํ์ํค๊ธฐ
import React, { useEffect, useState, useRef } from "react";
import "./App.css";
const App = () => {
const [count, setCount] = useState(1);
const [renderCount, setRenderCount] = useState(1);
useEffect(() => {
console.log("๋ ๋๋ง");
setRenderCount(renderCount + 1);
});
return (
<div>
<h1>Count: {count}</h1>
<h1>๋ ๋๋ง: {renderCount}</h1>
<button onClick={() => setCount(count + 1)}>count +</button>
</div>
);
};
export default App;
ํ์ง๋ง ์ด๋ ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋์์์ด ๋ ๋๋ง์ด ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
์ useEffect๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฌดํ ๋ฐ๋ณต์ด ๋ ๊น?
1. ๋ฒํผ์ ํด๋ฆญํ๋ฉด setCount๋ก ์ธํด count ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค. ๊ทธ๋์ ๋ ๋๋ง์ด ๋๊ธฐ ๋๋ฌธ์ useEffect๋ ํธ์ถ๋ฉ๋๋ค.
2. useEffect ๋ด๋ถ์๋ renderCount๋ฅผ ์ ๋ฐ์ดํธํ๋ ์ฝ๋๊ฐ ์กด์ฌํฉ๋๋ค. ์ฆ, renderCount ๊ฐ์ด ๋ณ๊ฒฝ๋ฉ๋๋ค.
3. state ๊ฐ์ด ๋ณ๊ฒฝ๋์๊ธฐ ๋๋ฌธ์ ๋ค์ useEffect๋ฅผ ํธ์ถํฉ๋๋ค ... ๋ฐ๋ณต
useRef ์ด์ฉํ๊ธฐ
๊ทธ๋์ ๋ค์๊ณผ ๊ฐ์ด useRef๋ฅผ ์ฌ์ฉํ์ฌ ๋ ๋๋ง ์๋ฅผ renderCount.current๋ก ๋ณด์ฌ์ฃผ๊ฒ ์ต๋๋ค.
const App = () => {
const [count, setCount] = useState(1);
const renderCount = useRef(1);
useEffect(() => {
renderCount.current = renderCount.current + 1;
console.log("๋ ๋๋ง ์: ", renderCount.current);
});
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>count +</button>
</div>
);
};
export default App;
์ค๋ฅ ์์ด ์ฝ์์์ ํ์ธ์ด ๊ฐ๋ฅํฉ๋๋ค. ๊ทธ๋ฐ๋ฐ, Count๋ 1์ธ๋ฐ ๋ ๋๋ง ์๋ 2๋ผ๊ณ ํ์๊ฐ ๋์์ต๋๋ค.
์ด์ ๋ ๋จผ์ renderCount๋ฅผ useRef(1)์ ํตํด 1๋ก ์ด๊ธฐํ ํ๊ณ , ํ๋ฉด์ ์ฒ์ ๋ ๋๋งํ๋ฉด์ renderCount.current + 1์ ํ๋ฉด์ 2๊ฐ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด์ ๋ฒํผ์ ํด๋ฆญํ ๋๋ง๋ค ์ฝ์์์ ์ ์์ ์ผ๋ก ๋ฐ๋ ๋ ๋๋ง ์๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ useRef๋ ๋ณํ๋ ๊ฐ์งํด์ผ ํ์ง๋ง, ๋ ๋๋ง์ ๋ฐ์์ํค๋ฉด ์ ๋๋ ๊ฐ์ ๋ค๋ฃฐ ๋ ์ฌ์ฉํ๋ฉด ์ ์ฉํฉ๋๋ค.
์ฐธ๊ณ ์๋ฃ
https://www.youtube.com/watch?v=VxqZrL4FLz8&list=PLZ5oZ2KmQEYjwhSxjB_74PoU6pmFzgVMO&index=3