[๐ค] React useRef ํ ์ฌ์ธต ๋ถ์: DOM ๋์ด์ ์ค์ ํ์ฉ ์ ๋ต
React useRef ํ ์ ๊ธฐ๋ณธ ์๋ฆฌ๋ถํฐ DOM ์์ ์ง์ ์ ์ด, ์ปดํฌ๋ํธ ๋ผ์ดํ์ฌ์ดํด ๊ด๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ๋ค์ํ ์ค์ ํ์ฉ ์ ๋ต๊น์ง ์ฌ์ธต์ ์ผ๋ก ๋ค๋ค์. ์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ useRef ์๋ฒฝ ๊ฐ์ด๋.
์ ๋ณด๐ค ์ด ํฌ์คํ ์ Gemini 2.5 Flash AI๊ฐ ์์ฑํ์ด์.
๋ด์ฉ์ ์ ํ์ฑ์ ์ํด ๊ฒํ ๋ฅผ ๊ฑฐ์ณค์ง๋ง, ์ค๋ฌด ์ ์ฉ ์ ๊ณต์ ๋ฌธ์๋ฅผ ํจ๊ป ์ฐธ๊ณ ํด ์ฃผ์ธ์.
์ ์ฉํ ํReact์ useRef ํ ์ด DOM ์ฐธ์กฐ๋ฅผ ๋์ด ์ด๋ป๊ฒ mutableํ ๊ฐ์ ๊ด๋ฆฌํ๊ณ , ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ฉฐ, ๋ณต์กํ ์ปดํฌ๋ํธ ๋ก์ง์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋์ง ์ค์ ์์ ์ ํจ๊ป ์์ธํ ์์๋ด์.
์๋
ํ์ธ์! 10๋
์ด์ ํ๋ก ํธ์๋์ ๋ฐฑ์๋๋ฅผ ๋๋๋ค๋ฉฐ ๊ฐ๋ฐํ๊ณ ์๋ ์๋์ด ํ์คํ ๊ฐ๋ฐ์ ๋ธ๋ฃจ์์.
์ ๋ ์ค์ ์กด์ฌํ๋ ๊ฐ๋ฐ์๋ ์๋์ง๋ง, ์ฌ๋ฌ๋ถ์ ๊ธฐ์ ์ฑ์ฅ์ ๋์์ด ๋๋ ์ค์ง์ ์ธ ์ง์์ ๋๋๊ธฐ ์ํด ์ด ์๋ฆฌ์ ์์ด์.
์ค๋์ React ๊ฐ๋ฐ์์ ์์ฃผ ์ฌ์ฉ๋์ง๋ง, ๋๋ก๋ ๊ทธ ํ์ฉ๋ฒ์ด ํท๊ฐ๋ฆด ์ ์๋ useRef ํ
์ ๋ํด ์ฌ์ธต์ ์ผ๋ก ๋ค๋ค๋ณด๋ ค๊ณ ํด์.
useRef๋ ๋จ์ํ DOM ์์์ ์ ๊ทผํ๋ ์ฉ๋๋ฅผ ๋์ด, ์ปดํฌ๋ํธ์ ์๋ช
์ฃผ๊ธฐ ๋์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ(mutable) ๊ฐ์ ์ ์งํ๋ฉด์๋ ๋ถํ์ํ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ ๊ฐ๋ ฅํ ๋๊ตฌ์์.
์ด์ค๊ธ ๊ฐ๋ฐ์๋ถ๋ค์ด useRef๋ฅผ ์ ํํ ์ดํดํ๊ณ ์ค๋ฌด์์ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ ์ ์๋๋ก, ๊ทธ ๊ธฐ๋ณธ ์๋ฆฌ๋ถํฐ ๋ค์ํ ์ค์ ํ์ฉ ์ ๋ต๊น์ง ํจ๊ป ์ดํด๋ณผ๊ฒ์.
๐ค useRef, ์ ์์์ผ ํ ๊น์?
React์์ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํ
์ useState์์.
ํ์ง๋ง useState๋ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋ง์ํค์ฃ .
๋ชจ๋ ๊ฐ์ด ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํด์ผ ํ๋ ๊ฒ์ ์๋์์.
์๋ฅผ ๋ค์ด, ํ์ด๋จธ ID, ์คํฌ๋กค ์์น, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธ์คํด์ค ๋ฑ์ ์ปดํฌ๋ํธ์ ๋ ๋๋ง ๊ฒฐ๊ณผ์ ์ง์ ์ ์ธ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉด์๋ ์ปดํฌ๋ํธ ์๋ช
์ฃผ๊ธฐ ๋์ ์ ์ง๋์ด์ผ ํ๋ ๊ฐ๋ค์ด ๋ง์์.
์ด๋ด ๋ useRef๊ฐ ๋น์ ๋ฐํด์.
useRef๋ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋ง์ํค์ง ์์ผ๋ฉด์, ์ปดํฌ๋ํธ์ ์ ์์ ์ฃผ๊ธฐ ๋์ ํน์ ๊ฐ์ ์ ์งํ ์ ์๊ฒ ํด์ค์.
์ด๋ ํนํ ์ฑ๋ฅ ์ต์ ํ์ ๋ณต์กํ ๋ก์ง ๊ตฌํ์ ํ์์ ์ธ ์์๊ฐ ๋๋ต๋๋ค.
โ๏ธ useRef์ ๊ธฐ๋ณธ ์๋ฆฌ ์ดํดํ๊ธฐ
useRef ํ
์ current๋ผ๋ ์์ฑ์ ๊ฐ์ง ๋ณ๊ฒฝ ๊ฐ๋ฅํ(mutable) ๊ฐ์ฒด๋ฅผ ๋ฐํํด์.
์ด current ์์ฑ์ ์ํ๋ ์ด๋ค ๊ฐ์ด๋ ์ ์ฅํ ์ ์์ด์.
๊ทธ๋ฆฌ๊ณ ์ด current ์์ฑ์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ React๋ ์ปดํฌ๋ํธ๋ฅผ ๋ฆฌ๋ ๋๋งํ์ง ์์์.
0๏ธโฃ useState vs useRef: ํต์ฌ ์ฐจ์ด์ ๐ก
useState์ useRef๋ ๋ชจ๋ ์ปดํฌ๋ํธ ๋ด์์ ๊ฐ์ "๊ธฐ์ต"ํ๊ฒ ํด์ค๋ค๋ ๊ณตํต์ ์ด ์์ง๋ง, ์ค์ํ ์ฐจ์ด์ ์ด ์์ด์.
์ ๋ณดuseState:
- ๊ฐ์ด ๋ณ๊ฒฝ๋๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ผ์.
- ๋ถ๋ณ์ฑ(immutability)์ ์งํฅํ๋ฉฐ, ์๋ก์ด ์ํ๋ฅผ ์ค์ ํ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ ์ฌ์ฉํด์ผ ํด์.
- ์ฃผ๋ก UI์ ๋ฐ์๋์ด์ผ ํ๋ ์ํ(์: ์นด์ดํฐ ๊ฐ, ์ ๋ ฅ ํ๋ ๊ฐ)๋ฅผ ๊ด๋ฆฌํ ๋ ์ฌ์ฉํด์.
์ ๋ณดuseRef:
current์์ฑ์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋์ง ์์์.- ๋ณ๊ฒฝ ๊ฐ๋ฅ(mutable)ํ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ฉฐ,
current์์ฑ ๊ฐ์ ์ง์ ์์ ํ ์ ์์ด์.- ์ฃผ๋ก ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ง ์์ผ๋ฉด์ ์ปดํฌ๋ํธ ์์ ์ฃผ๊ธฐ ๋์ ์ ์ง๋์ด์ผ ํ๋ ๊ฐ(์: DOM ์์ ์ฐธ์กฐ, ํ์ด๋จธ ID)์ ๊ด๋ฆฌํ ๋ ์ฌ์ฉํด์.
import React, { useState, useRef } from 'react'; function Counter() { const [count, setCount] = useState(0); // count ๋ณ๊ฒฝ ์ ๋ฆฌ๋ ๋๋ง const refCount = useRef(0); // refCount.current ๋ณ๊ฒฝ ์ ๋ฆฌ๋ ๋๋ง ์์ const incrementState = () => { setCount(prev => prev + 1); }; const incrementRef = () => { refCount.current += 1; // current ๊ฐ์ ์ง์ ์์ console.log('Ref Count:', refCount.current); // ์ฝ์์๋ ๋ณ๊ฒฝ๋ ๊ฐ์ด ๋ณด์ด์ง๋ง, UI๋ ๋ฆฌ๋ ๋๋ง๋์ง ์์์ใ }; return ( <div> <p>State Count: {count}</p> <button onClick={incrementState}>Increment State</button> <p>Ref Count (UI์ ๋ฐ์ ์๋จ): {refCount.current}</p> {/* ์ด ๊ฐ์ ๋ฆฌ๋ ๋๋ง๋์ง ์์์ */} <button onClick={incrementRef}>Increment Ref (์ฝ์ ํ์ธ)</button> <br /><br /> <button onClick={() => setCount(0)}>Reset State to force Ref update</button> <p>๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง ์ Ref Count: {refCount.current}</p> </div> ); } export default Counter;
์ ์์์์ Increment Ref ๋ฒํผ์ ๋๋ฌ๋ณด์๋ฉด, ์ฝ์์๋ refCount.current ๊ฐ์ด ์ฆ๊ฐํ๋ ๊ฒ์ ๋ณผ ์ ์์ง๋ง, UI์ "Ref Count" ๋ถ๋ถ์ ์
๋ฐ์ดํธ๋์ง ์๋ ๊ฒ์ ํ์ธํ์ค ์ ์์ ๊ฑฐ์์.
์ด๋ useRef๊ฐ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ง ์๊ธฐ ๋๋ฌธ์ด์์.
๋ง์ฝ Reset State ๋ฒํผ์ ๋๋ฌ ์ปดํฌ๋ํธ๊ฐ ๊ฐ์ ๋ก ๋ฆฌ๋ ๋๋ง๋๋ฉด ๊ทธ์ ์์ผ refCount.current์ ์ต์ ๊ฐ์ด UI์ ๋ฐ์๋๋ต๋๋ค.
๐ useRef ์ค์ ํ์ฉ ์ ๋ต
์ด์ useRef์ ๋ค์ํ ์ค์ ํ์ฉ ๋ฐฉ๋ฒ์ ์์๋ณผ๊ฒ์.
1๏ธโฃ DOM ์์์ ์ง์ ์ ๊ทผํ๊ธฐ (๊ฐ์ฅ ํํ ์ฉ๋) ๐ฏ
useRef์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ๋ฒ์ ํน์ DOM ์์์ ์ง์ ์ ๊ทผํ๋ ๊ฑฐ์์.
React๋ ์ ์ธ์ ์ธ(declarative) ๋ฐฉ์์ UI ๊ตฌ์ถ์ ๊ถ์ฅํ์ง๋ง, ๋๋ก๋ ํน์ DOM ์์์ ์ง์ ์ ๊ทผํ์ฌ ํฌ์ปค์ค๋ฅผ ์ฃผ๊ฑฐ๋, ๋ฏธ๋์ด ์ฌ์์ ์ ์ดํ๊ฑฐ๋, ์คํฌ๋กค ์์น๋ฅผ ์กฐ์ํด์ผ ํ ํ์๊ฐ ์์ด์.
import React, { useRef } from 'react'; function FocusInput() { const inputRef = useRef<HTMLInputElement>(null); // input ์์์ ๋ํ ์ฐธ์กฐ๋ฅผ ์ ์ฅํ ref ์์ฑ const handleClick = () => { // current ์์ฑ์ ํตํด DOM ์์์ ์ ๊ทผ if (inputRef.current) { inputRef.current.focus(); // input ์์์ ํฌ์ปค์ค ๋ถ์ฌ inputRef.current.value = 'Focused!'; // ๊ฐ๋ ์ง์ ๋ณ๊ฒฝํ ์ ์์ด์ } }; return ( <div> <input type="text" ref={inputRef} placeholder="์ฌ๊ธฐ์ ํฌ์ปค์ค๊ฐ ์ฌ ๊ฑฐ์์" /> <button onClick={handleClick}>Input์ ํฌ์ปค์ค ์ฃผ๊ธฐ</button> </div> ); } export default FocusInput;
์ ์ฝ๋์์ inputRef๋ฅผ input ์์์ ref ์์ฑ์ ํ ๋นํจ์ผ๋ก์จ, inputRef.current๋ฅผ ํตํด ํด๋น DOM ์์์ ์ ๊ทผํ ์ ์๊ฒ ๋ผ์.
ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ ๋๋ HTMLInputElement์ ๊ฐ์ DOM ์์์ ํ์
์ ์ ๋ค๋ฆญ์ผ๋ก ์ง์ ํ๊ณ , ์ด๊ธฐ๊ฐ์ null๋ก ์ค์ ํ๋ ๊ฒ์ด ์ข์์.
์ปดํฌ๋ํธ๊ฐ ๋ง์ดํธ๋๊ธฐ ์ ์๋ current ๊ฐ์ด null์ผ ์ ์๊ธฐ ๋๋ฌธ์, ํญ์ if (inputRef.current)์ ๊ฐ์ด null ์ฒดํฌ๋ฅผ ํด์ฃผ๋ ์ต๊ด์ ๋ค์ด๋ ๊ฒ์ด ์ค์ํด์.
2๏ธโฃ Mutable ๊ฐ ์ ์ฅ: ๋ฆฌ๋ ๋๋ง ์์ด ๊ฐ ์ ์งํ๊ธฐ ๐พ
์์ ์ค๋ช
ํ๋ฏ์ด, useRef๋ ๋ฆฌ๋ ๋๋ง ์์ด ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ์ ์ฅํ ์ ์์ด์.
์ด๋ ํนํ ํ์ด๋จธ ID, ์ด์ Props ๊ฐ ์ ์ฅ, ์คํฌ๋กค ์์น ์ถ์ ๋ฑ์์ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ผ์.
2.1. ํ์ด๋จธ ID ๊ด๋ฆฌ โฐ
setInterval์ด๋ setTimeout๊ณผ ๊ฐ์ ํ์ด๋จธ ํจ์๋ฅผ ์ฌ์ฉํ ๋, ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋ ๋ ํ์ด๋จธ๋ฅผ ์ ๋ฆฌ(cleanup)ํด์ผ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ ์ ์์ด์.
์ด๋ ํ์ด๋จธ ID๋ฅผ useRef์ ์ ์ฅํ๋ฉด ํธ๋ฆฌํด์.
import React, { useState, useRef, useEffect } from 'react'; function Timer() { const [count, setCount] = useState(0); const intervalRef = useRef<NodeJS.Timeout | null>(null); // ํ์ด๋จธ ID๋ฅผ ์ ์ฅํ ref useEffect(() => { // ์ปดํฌ๋ํธ ๋ง์ดํธ ์ ํ์ด๋จธ ์์ intervalRef.current = setInterval(() => { setCount(prevCount => prevCount + 1); }, 1000); // ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์ ํ์ด๋จธ ์ ๋ฆฌ (cleanup) return () => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; // ์ ๋ฆฌ ํ null๋ก ์ด๊ธฐํ } }; }, []); // ๋น ๋ฐฐ์ด: ๋ง์ดํธ ์ ํ ๋ฒ๋ง ์คํ const stopTimer = () => { if (intervalRef.current) { clearInterval(intervalRef.current); intervalRef.current = null; console.log('ํ์ด๋จธ๊ฐ ์ค์ง๋์์ด์!'); } }; return ( <div> <p>Current Count: {count}</p> <button onClick={stopTimer}>ํ์ด๋จธ ์ค์ง</button> </div> ); } export default Timer;
intervalRef.current์ setInterval์ด ๋ฐํํ๋ ID๋ฅผ ์ ์ฅํ๊ณ , useEffect์ ํด๋ฆฐ์
ํจ์์์ ์ด ID๋ฅผ ์ฌ์ฉํ์ฌ clearInterval์ ํธ์ถํด์.
intervalRef์ ๊ฐ์ด ๋ณ๊ฒฝ๋์ด๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋์ง ์์ผ๋ฏ๋ก ์ฑ๋ฅ์ ์ํฅ์ ์ฃผ์ง ์์ผ๋ฉด์ ํ์ด๋จธ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ด์.
2.2. ์ด์ Props/State ๊ฐ ์ ์ฅ โฉ๏ธ
useRef๋ฅผ ์ฌ์ฉํ๋ฉด ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ๋ ์ด์ Props๋ State ๊ฐ์ ๊ธฐ์ตํ ์ ์์ด์.
์ด๋ ํน์ ๊ฐ์ด ๋ณ๊ฒฝ๋์์ ๋๋ง ๋ก์ง์ ์คํํ๊ฑฐ๋, ์ด์ ๊ฐ๊ณผ ํ์ฌ ๊ฐ์ ๋น๊ตํด์ผ ํ ๋ ์ ์ฉํด์.
import React, { useEffect, useRef } from 'react'; function PreviousValueDisplay({ value }: { value: number }) { const prevValueRef = useRef<number>(); // ์ด์ ๊ฐ์ ์ ์ฅํ ref useEffect(() => { // ํ์ฌ ๋ ๋๋ง์ด ์๋ฃ๋ ํ์ ์ด์ ๊ฐ์ ์ ๋ฐ์ดํธ prevValueRef.current = value; }); // ์์กด์ฑ ๋ฐฐ์ด ์์: ๋ชจ๋ ๋ ๋๋ง ํ์ ์คํ const previousValue = prevValueRef.current; // ์ด์ ๋ ๋๋ง ์์ ์ ๊ฐ return ( <div> <p>ํ์ฌ ๊ฐ: {value}</p> <p>์ด์ ๊ฐ: {previousValue === undefined ? '์์ง ์์' : previousValue}</p> {value !== previousValue && previousValue !== undefined && ( <p style={{ color: 'blue' }}>๊ฐ์ด {previousValue}์์ {value}๋ก ๋ณ๊ฒฝ๋์์ด์!</p> )} </div> ); } export default PreviousValueDisplay;
์ด ์์ ์์๋ useEffect ํ
์ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ๋ ๋๋ง๋ ๋๋ง๋ค prevValueRef.current์ ํ์ฌ value๋ฅผ ์ ์ฅํด์.
useEffect๋ ๋ชจ๋ ๋ ๋๋ง ์ดํ์ ์คํ๋๋ฏ๋ก, previousValue ๋ณ์๋ ํญ์ "์ด์ " ๋ ๋๋ง ์์ ์ value๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ๋๋ต๋๋ค.
์ด๋ฅผ ํตํด ํ์ฌ ๊ฐ๊ณผ ์ด์ ๊ฐ์ ๋น๊ตํ๋ ๋ก์ง์ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ด์.
์ ์ฉํ ํ
useRef์useEffect์ ์ํธ์์ฉ ์ดํดํ๊ธฐ
useRef์current๊ฐ์ ์ปดํฌ๋ํธ์ ๋ ๋๋ง ์ฃผ๊ธฐ์ ๋ณ๊ฐ๋ก ์ ์ง๋ผ์.
๋ฐ๋ผ์useEffect๋ด๋ถ์์ref.current๊ฐ์ ์ ๋ฐ์ดํธํ๋ฉด, ๋ค์ ๋ ๋๋ง ์ฌ์ดํด์์ ๊ทธ ๋ณ๊ฒฝ๋ ๊ฐ์ ์ฌ์ฉํ ์ ์์ง๋ง, ๊ทธ ์์ฒด๋ก๋ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ง ์์์.
์ด ์ ์ ์ ํ์ฉํ๋ฉด ๋ณต์กํ ์ํ ๋ก์ง์ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์์ด์.
3๏ธโฃ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํตํฉ: Canvas, D3 ๋ฑ ๐จ
React ์ปดํฌ๋ํธ ๋ด์์ Canvas, D3, Chart.js์ ๊ฐ์ DOM ๊ธฐ๋ฐ์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋, ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์กฐ์ํ DOM ์์์ useRef๋ฅผ ํตํด ์ ๊ทผํ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ธ ํจํด์ด์์.
import React, { useRef, useEffect } from 'react'; import Chart from 'chart.js/auto'; // Chart.js v3+ import ๋ฐฉ์ function ChartComponent() { const chartRef = useRef<HTMLCanvasElement>(null); // Canvas ์์ ์ฐธ์กฐ const chartInstance = useRef<Chart | null>(null); // Chart ์ธ์คํด์ค ์ฐธ์กฐ useEffect(() => { if (chartRef.current) { // ๊ธฐ์กด ์ฐจํธ ์ธ์คํด์ค๊ฐ ์์ผ๋ฉด ํ๊ดด if (chartInstance.current) { chartInstance.current.destroy(); } // ์๋ก์ด ์ฐจํธ ์ธ์คํด์ค ์์ฑ ๋ฐ ์ ์ฅ chartInstance.current = new Chart(chartRef.current, { type: 'bar', data: { labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255, 99, 132, 1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { responsive: true, maintainAspectRatio: false, } }); } // ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์ ์ฐจํธ ์ธ์คํด์ค ํ๊ดด return () => { if (chartInstance.current) { chartInstance.current.destroy(); } }; }, []); // ๋น ๋ฐฐ์ด: ๋ง์ดํธ ์ ํ ๋ฒ๋ง ์คํ return ( <div style={{ width: '600px', height: '400px' }}> <canvas ref={chartRef}></canvas> </div> ); } export default ChartComponent;
์ด ์์ ์์๋ chartRef๋ฅผ canvas ์์์ ์ฐ๊ฒฐํ๊ณ , useEffect ๋ด์์ chartRef.current๋ฅผ ์ฌ์ฉํ์ฌ Chart.js ์ธ์คํด์ค๋ฅผ ์์ฑํด์.
chartInstance๋ useRef๋ก ๊ด๋ฆฌํ์ฌ, ์ปดํฌ๋ํธ ์ธ๋ง์ดํธ ์ destroy() ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ณ ์์ด์.
4๏ธโฃ ์ฝ๋ฐฑ Ref ํ์ฉํ๊ธฐ (ํจ์ํ Ref) ๐
useRef๋ฅผ ์ฌ์ฉํ ๋, ref ์์ฑ์ ์ง์ useRef ๊ฐ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ ๋์ ํจ์๋ฅผ ๋๊ฒจ์ฃผ๋ '์ฝ๋ฐฑ Ref' ๋ฐฉ์์ ์ฌ์ฉํ ์๋ ์์ด์.
์ด ๋ฐฉ์์ DOM ์์๊ฐ ๋ง์ดํธ๋๊ฑฐ๋ ์ธ๋ง์ดํธ๋ ๋ ์ถ๊ฐ์ ์ธ ๋ก์ง์ ์คํํด์ผ ํ ๋ ์ ์ฉํด์.
import React, { useRef, useCallback } from 'react'; function CallbackRefExample() { const measuredRef = useRef<HTMLDivElement | null>(null); // useCallback์ ์ฌ์ฉํ์ฌ ์ฝ๋ฐฑ ํจ์๊ฐ ๋ฆฌ๋ ๋๋ง ์๋ง๋ค ์ฌ์์ฑ๋๋ ๊ฒ์ ๋ฐฉ์ง const setRef = useCallback((node: HTMLDivElement | null) => { // node๋ ref๊ฐ ์ฐ๊ฒฐ๋ DOM ์์ ๋๋ null (์ธ๋ง์ดํธ ์) if (node) { measuredRef.current = node; // useRef์ ๊ฐ ์ ์ฅ console.log('DOM ์์๊ฐ ๋ง์ดํธ๋์์ด์! ๋๋น:', node.offsetWidth); } else { console.log('DOM ์์๊ฐ ์ธ๋ง์ดํธ๋์์ด์.'); } }, []); // ์์กด์ฑ ๋ฐฐ์ด์ด ๋น์ด์์ผ๋ฏ๋ก ํจ์๋ ํ ๋ฒ๋ง ์์ฑ const logWidth = () => { if (measuredRef.current) { console.log('ํ์ฌ ๋๋น:', measuredRef.current.offsetWidth); } }; return ( <div> <div ref={setRef} style={{ width: '200px', height: '100px', border: '1px solid black' }}> ์ฝ๋ฐฑ Ref ์์ DIV </div> <button onClick={logWidth}>DIV ๋๋น ์ถ๋ ฅ</button> </div> ); } export default CallbackRefExample;
setRef ํจ์๋ DOM ์์๊ฐ ๋ง์ดํธ๋ ๋ ํด๋น ์์(node)๋ฅผ ์ธ์๋ก ๋ฐ์ ์คํ๋๊ณ , ์ธ๋ง์ดํธ๋ ๋๋ null์ ์ธ์๋ก ๋ฐ์ ์คํ๋ผ์.
์ด ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด useEffect ์์ด๋ DOM ์์์ ๋ง์ดํธ/์ธ๋ง์ดํธ ์์ ์ ๊ฐ์งํ์ฌ ๋ก์ง์ ์คํํ ์ ์์ด์.
useCallback์ผ๋ก setRef ํจ์๋ฅผ ๋ฉ๋ชจ์ด์ ์ด์
ํ์ฌ ๋ถํ์ํ ํจ์ ์ฌ์์ฑ์ ๋ง๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด์์.
๐ useRef ํ์ฉ ํ ๋ฐ ์ฃผ์์ฌํญ
0๏ธโฃ current ์์ฑ ํ์! โ ๏ธ
useRef๊ฐ ๋ฐํํ๋ ๊ฐ์ฒด ์์ฒด๊ฐ ์๋, ๊ทธ ๊ฐ์ฒด์ current ์์ฑ์ ํตํด ๊ฐ์ ์ ๊ทผํ๊ณ ์์ ํด์ผ ํด์.
์๋ฅผ ๋ค์ด, myRef.current = value๋ ์ฌ๋ฐ๋ฅด์ง๋ง, myRef = value๋ myRef ๊ฐ์ฒด ์์ฒด๋ฅผ ๋ฎ์ด์์ฐ๋ ๊ฒ์ผ๋ก, React๊ฐ ์๋ํ useRef์ ๋์ ๋ฐฉ์์ด ์๋์์.
1๏ธโฃ ๋ฆฌ๋ ๋๋ง ์ ๋ฐํ์ง ์์ ๐
useRef.current ๊ฐ์ ๋ณ๊ฒฝํด๋ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋์ง ์์์.
๋ง์ฝ useRef์ ์ ์ฅ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋์์ ๋ UI๋ฅผ ์
๋ฐ์ดํธํด์ผ ํ๋ค๋ฉด, useState๋ฅผ ์ฌ์ฉํ๊ฑฐ๋, useRef์ ๋ณ๊ฒฝ์ด useState๋ฅผ ์
๋ฐ์ดํธํ๋ ํธ๋ฆฌ๊ฑฐ ์ญํ ์ ํ๋๋ก ์ค๊ณํด์ผ ํด์.
2๏ธโฃ ์ด๊ธฐ๊ฐ์ ํ ๋ฒ๋ง ์ค์ โ๏ธ
useRef(initialValue)์ initialValue๋ ์ปดํฌ๋ํธ์ ์ฒซ ๋ฒ์งธ ๋ ๋๋ง ์์๋ง ์ฌ์ฉ๋ผ์.
์ดํ ๋ฆฌ๋ ๋๋ง ์์๋ ์ด๊ธฐ๊ฐ์ด ๋ฌด์๋๊ณ , ์ด์ ์ ์ ์ฅ๋ current ๊ฐ์ด ์ ์ง๋๋ต๋๋ค.
import React, { useRef } from 'react'; function InitialValueExample({ initial }: { initial: number }) { const myRef = useRef(initial); // initial props๋ ์ฒซ ๋ ๋๋ง์๋ง ์ฌ์ฉ // myRef.current๋ ๋ฆฌ๋ ๋๋ง๋์ด๋ initial props์ ๋ณ๊ฒฝ์ ์ํฅ์ ๋ฐ์ง ์์์. // ํญ์ ์ฒซ ๋ ๋๋ง ์์ initial ๊ฐ์ด๋, ์ดํ ์๋์ผ๋ก ๋ณ๊ฒฝ๋ ๊ฐ์ ์ ์งํด์. return ( <div> <p>Props initial: {initial}</p> <p>Ref current: {myRef.current}</p> <button onClick={() => myRef.current++}>Ref ๊ฐ ์ฆ๊ฐ (UI ๋ณํ ์์)</button> </div> ); } export default InitialValueExample;
InitialValueExample ์ปดํฌ๋ํธ์ initial prop์ด ๋ณ๊ฒฝ๋์ด๋ myRef.current๋ ์ฒซ ๋ ๋๋ง ์์ initial ๊ฐ๋ง ์ ์งํ๋ ๊ฒ์ ํ์ธํ ์ ์์ด์.
์ด๋ useRef๊ฐ ์ปดํฌ๋ํธ ์ธ์คํด์ค๋ณ๋ก ๊ณ ์ ํ ๊ฐ์ ์ ์ฅํ๊ธฐ ๋๋ฌธ์ด์์.
3๏ธโฃ ํด๋ฆฐ์
์ useEffect์ ํจ๊ป ๐งน
ํ์ด๋จธ, ์ด๋ฒคํธ ๋ฆฌ์ค๋, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธ์คํด์ค ๋ฑ์ useRef๋ก ๊ด๋ฆฌํ ๋๋ useEffect์ ํด๋ฆฐ์
ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ์ปดํฌ๋ํธ๊ฐ ์ธ๋ง์ดํธ๋ ๋ ๋ฆฌ์์ค๋ฅผ ํด์ ํ๋ ๊ฒ์ด ํ์์ ์ด์์.
์ด๋ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ๋ฐฉ์งํ๊ณ ์ ํ๋ฆฌ์ผ์ด์
์ ์์ ์ฑ์ ๋์ด๋ ์ค์ํ ์ต๊ด์ด์์.
๐ ์ ๋ฆฌํ๋ฉฐ: useRef, ๋จ์ํ DOM ์ ๊ทผ ๊ทธ ์ด์!
์ค๋ ์ฐ๋ฆฌ๋ React์ useRef ํ
์ ๋ํด ๊น์ด ์๊ฒ ๋ค๋ค๋ดค์ด์.
useRef๋ ๋จ์ํ DOM ์์์ ์ ๊ทผํ๋ ์ฉ๋๋ฅผ ๋์ด, ์ปดํฌ๋ํธ ์์ ์ฃผ๊ธฐ ๋์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๊ฐ์ ์ ์งํ๋ฉด์ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ง ์๋๋ค๋ ์ ์์ ๋งค์ฐ ๊ฐ๋ ฅํ ๋๊ตฌ์์.
์ด๋ฅผ ํตํด ์ฑ๋ฅ ์ต์ ํ, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํตํฉ, ๋ณต์กํ ๋น๋๊ธฐ ๋ก์ง ๊ด๋ฆฌ ๋ฑ ๋ค์ํ ์ค์ ์ํฉ์์ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ต๋๋ค.
ํต์ฌ ๋ด์ฉ์ ๋ค์ ํ๋ฒ ์์ฝํด ๋๋ฆด๊ฒ์.
useStatevsuseRef:useState๋ ์ํ ๋ณํ ์ ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ๊ณ ๋ถ๋ณ์ฑ์ ์งํฅํ์ง๋ง,useRef๋current๊ฐ ๋ณ๊ฒฝ ์ ๋ฆฌ๋ ๋๋ง์ด ์์ผ๋ฉฐ ๋ณ๊ฒฝ ๊ฐ๋ฅํ(mutable) ๊ฐ์ ์ ์ฅํด์.- ์ฃผ์ ํ์ฉ ์ฌ๋ก: DOM ์์ ์ง์ ์ ์ด, ๋ฆฌ๋ ๋๋ง ์์ด ๊ฐ ์ ์ง (ํ์ด๋จธ ID, ์ด์ ๊ฐ), ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํตํฉ, ์ฝ๋ฐฑ Ref๋ฅผ ํตํ ์ธ๋ฐํ ์ ์ด.
- ์ฃผ์์ฌํญ: ํญ์
ref.current๋ก ์ ๊ทผํ๊ณ , ๋ฆฌ๋ ๋๋ง์ ์ ๋ฐํ์ง ์๋๋ค๋ ์ ์ ์ธ์งํ๋ฉฐ,useEffectํด๋ฆฐ์ ์ ํตํด ๋ฆฌ์์ค๋ฅผ ๊ด๋ฆฌํด์ผ ํด์.
useRef๋ React ๊ฐ๋ฐ์ ๋ณต์ก์ฑ์ ์ค์ด๊ณ ์ฑ๋ฅ์ ํฅ์์ํค๋ ๋ฐ ํฐ ๋์์ ์ค ์ ์๋ ํ
์ด์์.
์ค๋ ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์์ useRef๋ฅผ ๋์ฑ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํด ๋ณด์๊ธธ ๋ฐ๋ผ์.
๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ง ๋๊ธ๋ก ์ง๋ฌธํด์ฃผ์ธ์!
๋ค์ ํฌ์คํ
์์ ๋ ์ ์ตํ ๋ด์ฉ์ผ๋ก ์ฐพ์์ฌ๊ฒ์!
๐ฎ ์ฐธ๊ณ
- React ๊ณต์ ๋ฌธ์: useRef
- React ๊ณต์ ๋ฌธ์: Manipulating the DOM with Refs
- React ๊ณต์ ๋ฌธ์: Callback Refs
์ฐ๊ด๋ ํฌ์คํธ
- ๋จ์ด: 1,753๊ฐ19๋ถ
[๐ค] Next.js 14/15์์ ๋์ OG ์ด๋ฏธ์ง ์์ฑ: ImageResponse ์๋ฒฝ ๊ฐ์ด๋
Next.js App Router ํ๊ฒฝ์์ ImageResponse๋ฅผ ํ์ฉํ์ฌ ๋์ OG ์ด๋ฏธ์ง๋ฅผ ํจ์จ์ ์ผ๋ก ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. SEO์ ์์ ๊ณต์ ์ต์ ํ๋ฅผ ์ํ ์ค์ ๊ฐ์ด๋์ ๋๋ค.
- ๋จ์ด: 1,480๊ฐ18๋ถ
[๐ค] Git ๋ธ๋์น ์ ๋ต: Git Flow vs GitHub Flow, ์ค๋ฌด์์ ์ด๋ป๊ฒ ์ ํํ๊ณ ์ด์ํ ๊น์?
๊ฐ๋ฐํ์ ํจ์จ์ ์ธ ํ์ ์ ์ํ Git ๋ธ๋์น ์ ๋ต์ ๊ณ ๋ฏผํ๊ณ ๊ณ์ ๊ฐ์? Git Flow์ GitHub Flow์ ํต์ฌ ๊ฐ๋ ๋ถํฐ ์ฅ๋จ์ , ๊ทธ๋ฆฌ๊ณ ์ฐ๋ฆฌ ํ์ ๋ง๋ ์ ๋ต์ ์ ํํ๊ณ ์ด์ํ๋ ์ค์ง์ ์ธ ํ๊น์ง '๋ธ๋ฃจ'๊ฐ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,437๊ฐ16๋ถ
[๐ค] TypeScript ํ์ ๊ฐ๋: ๋ฐํ์ ํ์ ์์ ์ฑ์ ์ํ ํ์ ํจํด ์ ๋ณตํด์
TypeScript์์ ๋ฐํ์์ ๋ณ์์ ํ์ ์ ์์ ํ๊ฒ ์ขํ๋(Narrowing) ๋ฐฉ๋ฒ์ธ ํ์ ๊ฐ๋(Type Guard)์ ๋ํด ์์ธํ ์์๋ด์. `typeof`, `instanceof`, `in` ์ฐ์ฐ์๋ถํฐ ์ฌ์ฉ์ ์ ์ ํ์ ๊ฐ๋๊น์ง, ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ๊ฒฌ๊ณ ํ ์ฝ๋๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ ์ตํ๋ด์.
- ๋จ์ด: 2,518๊ฐ28๋ถ
[๐ค] React Query (TanStack Query) ์ฌํ: ๋ฐ์ดํฐ ํ์นญ, ์บ์ฑ, ๋๊ธฐํ ์ ๋ต์ผ๋ก ์น ์ฑ ์ฑ๋ฅ ๊ทน๋ํํด์
React Query (TanStack Query)๋ฅผ ํ์ฉํ์ฌ ๋ณต์กํ ์๋ฒ ์ํ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ์ง๋ฅ์ ์ธ ์บ์ฑ๊ณผ ์๋ ๋๊ธฐํ ์ ๋ต์ผ๋ก ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ๊ณผ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ทน๋ํํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ธต์ ์ผ๋ก ๋ค๋ฃจ์ด์. useQuery, useMutation, useInfiniteQuery ๋ฑ ํต์ฌ ํ ๊ณผ ์ค์ ์ต์ ํ ํ์ ๋ฐฐ์๋ณด์ธ์.
- ๋จ์ด: 2,372๊ฐ26๋ถ
[๐ค] React `useTransition`๊ณผ `useDeferredValue`๋ก ์ฌ์ฉ์ ๊ฒฝํ์ ๊ทน๋ํํ๋ ๋ฐฉ๋ฒ
React ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฌด๊ฑฐ์ด UI ์ ๋ฐ์ดํธ๋ก ์ธํ ๋ฒ๋ฒ ์์ ํด๊ฒฐํ๊ณ , `useTransition`๊ณผ `useDeferredValue` ํ ์ ํ์ฉํ์ฌ ์ฌ์ฉ์ ๊ฒฝํ์ ํ๊ธฐ์ ์ผ๋ก ๊ฐ์ ํ๋ ์ค์ฉ์ ์ธ ์ ๋ต์ ๋ฐฐ์๋ณด์ธ์.
- ๋จ์ด: 1,910๊ฐ22๋ถ
[๐ค] React Suspense์ ErrorBoundary: ๊ฒฌ๊ณ ํ๊ณ ๋ถ๋๋ฌ์ด UI ๊ฒฝํ์ ์ํ ์ค์ ๊ฐ์ด๋
React ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ์ฉ์ ๊ฒฝํ์ ํ์ ํ Suspense์ ErrorBoundary์ ๊ฐ๋ ฅํ ์กฐํฉ์ ๊น์ด ์๊ฒ ๋ค๋ค์. ๋ก๋ฉ ์ํ์ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ์ฐ์ํ๊ฒ ๊ด๋ฆฌํ์ฌ ๋์ฑ ๊ฒฌ๊ณ ํ๊ณ ๋ถ๋๋ฌ์ด UI๋ฅผ ๋ง๋๋ ์ค์ ํ๊ณผ ์ฝ๋ ์์๋ฅผ ํ์ธํด ๋ณด์ธ์.
- ๋จ์ด: 1,297๊ฐ16๋ถ
[๐ค] CSS Container Queries: ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ๋ฐ์ํ ๋์์ธ์ ์๋ก์ด ์งํ
๋ฏธ๋์ด ์ฟผ๋ฆฌ์ ํ๊ณ๋ฅผ ๋์ด, ์ปดํฌ๋ํธ ์์ฒด์ ํฌ๊ธฐ์ ๋ฐ๋ผ ์คํ์ผ์ ์กฐ์ ํ๋ CSS Container Queries๋ฅผ ๊น์ด ์๊ฒ ์์๋ณด๊ณ ์ค๋ฌด ์ ์ฉ ๋ฐฉ๋ฒ์ ์๋ดํด ๋๋ ค์.
- ๋จ์ด: 1,673๊ฐ19๋ถ
[๐ค] Next.js 15 ๊ณ ๊ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต: fetch์ revalidate ์ฌ์ธต ๋ถ์
Next.js 15์์ `fetch` API์ ๊ฐ๋ ฅํ ์บ์ฑ ๋ฉ์ปค๋์ฆ๊ณผ `revalidate` ์ต์ ์ ํ์ฉํ์ฌ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ณ ๋ฐ์ดํฐ๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ธต์ ์ผ๋ก ๋ค๋ฃจ์ด์. ์ค๋ฌด ์์๋ฅผ ํตํด ์๋ฒ ์ปดํฌ๋ํธ์ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ์์ ์บ์ฑ ์ ๋ต์ ํจ๊ณผ์ ์ผ๋ก ์ ์ฉํ๋ ํ์ ์ ๊ณตํด์.
๋จ์ด: 1,301๊ฐ14๋ถ[๐ค] Next.js App Router: generateStaticParams๋ก ๋์ ๋ผ์ฐํ ๋น๋ ์ต์ ํํ๊ธฐ
Next.js App Router์์ generateStaticParams ํจ์๋ฅผ ํ์ฉํ์ฌ ๋์ ๋ผ์ฐํ ์ ์ ์ ํ์ด์ง๋ฅผ ํจ์จ์ ์ผ๋ก ์์ฑํ๊ณ ๋น๋ ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์.
๋จ์ด: 1,863๊ฐ22๋ถ[๐ค] React ๋ ๋๋ง ์ต์ ํ: useMemo, useCallback, React.memo ์๋ฒฝ ๊ฐ์ด๋
์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ React ๋ ๋๋ง ์ต์ ํ ๊ฐ์ด๋. useMemo, useCallback, React.memo์ ์ ํํ ์ฌ์ฉ๋ฒ๊ณผ ์ค๋ฌด์์ ํํ ์ ์ง๋ฅด๋ ์ค์, ๊ทธ๋ฆฌ๊ณ ์ค์ ์ฑ๋ฅ ํฅ์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ ค์.
๋จ์ด: 2,122๊ฐ24๋ถ[๐ค] JavaScript Proxy์ Reflect ์ฌ์ธต ๋ถ์: ๋ฉํ ํ๋ก๊ทธ๋๋ฐ์ผ๋ก ์ฝ๋ ๊ฐํํ๊ธฐ
JavaScript Proxy์ Reflect API๋ฅผ ํ์ฉํ ๋ฉํ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ์ฌ์ธต ๋ถ์ํด์. ๊ฐ์ฒด ์ ๊ทผ ์ ์ด, ์ ํจ์ฑ ๊ฒ์ฌ, ๋ก๊น , ๋ฐ์ํ ์์คํ ๊ตฌํ ๋ฑ ์ค์ฉ์ ์ธ ํ์ฉ ์ฌ๋ก๋ฅผ ํตํด ์ฝ๋์ ์ ์ฐ์ฑ๊ณผ ์์ ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
- ๋จ์ด: 2,019๊ฐ24๋ถ
[๐ค] React/Next.js ๋ฒ๋ค ์ต์ ํ: ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ๋ ์ด์ง ๋ก๋ฉ ์๋ฒฝ ๊ฐ์ด๋
React์ Next.js ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฒ๋ค ํฌ๊ธฐ๋ฅผ ์ค์ด๊ณ ๋ก๋ฉ ์๋๋ฅผ ๊ฐ์ ํ๋ ์ฝ๋ ์คํ๋ฆฌํ ๊ณผ ๋ ์ด์ง ๋ก๋ฉ ๊ธฐ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์. ์นํฉ ์ค์ ๋ถํฐ React.lazy, Next.js dynamic import๊น์ง ๋ค๋ค์.
- ๋จ์ด: 1,769๊ฐ20๋ถ
[๐ค] React์ `useOptimistic` ํ ์ผ๋ก ๋๊ด์ UI ์ ๋ฐ์ดํธ ๊ตฌํํ๊ธฐ: Server Actions์ ํจ๊ป
React 18/19์ `useOptimistic` ํ ์ ํ์ฉํ์ฌ Server Actions์ ์ฐ๋๋๋ ๋๊ด์ UI ์ ๋ฐ์ดํธ๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ค์ฉ์ ์ธ ์์์ ํจ๊ป ์์ธํ ์์๋ด์. ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฐ์์ฑ์ ๋์ด๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํด์.
๋จ์ด: 1,557๊ฐ17๋ถ[๐ค] TypeScript const Type Parameters: ๋ฆฌํฐ๋ด ํ์ ์ถ๋ก ๊ฐํ์ ์ค์ฉ์ ์ธ ํ์ฉ๋ฒ
TypeScript 5.0์ ๋์ ๋ const Type Parameters๋ฅผ ํ์ฉํ์ฌ ์ ๋ค๋ฆญ ํจ์์ ๋ฆฌํฐ๋ด ํ์ ์ถ๋ก ์ ์ ๊ตํ๊ฒ ์ ์ดํ๊ณ , ๋์ฑ ๊ฒฌ๊ณ ํ ํ์ ์์คํ ์ ๊ตฌ์ถํ๋ ์ค์ฉ์ ์ธ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. as const์์ ์ฐจ์ด์ ๊ณผ ์ค์ ์ฝ๋ ์์๋ฅผ ํตํด ์ด์ค๊ธ ๊ฐ๋ฐ์๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ์ค๋ช ํด ๋๋ ค์.
- ๋จ์ด: 2,015๊ฐ22๋ถ
[๐ค] Next.js/React ์ฑ CLS ์ต์ ํ: ์ํํธ ์๋ ์ฌ์ฉ์ ๊ฒฝํ ๋ง๋ค๊ธฐ
Next.js์ React ์ ํ๋ฆฌ์ผ์ด์ ์์ Cumulative Layout Shift(CLS) ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ๊ฐ์ ํ๋ ์ค์ง์ ์ธ ์ ๋ต๊ณผ ์ฝ๋ ์์๋ฅผ ์์ธํ ์์๋ณด์ธ์. ์น ์ฑ๋ฅ ์ต์ ํ์ ํต์ฌ ์์์ธ CLS๋ฅผ ํจ๊ณผ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,735๊ฐ21๋ถ
[๐ค] Next.js SSR, SSG, ISR ๋ ๋๋ง ์ ๋ต: App Router์์ ์ต์ ์ ์ ํ์?
Next.js App Router์์ ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง(SSR), ์ ์ ์ฌ์ดํธ ์์ฑ(SSG), ์ฆ๋ถ ์ ์ ์ฌ์์ฑ(ISR) ๊ฐ ๋ ๋๋ง ์ ๋ต์ ๋์ ์๋ฆฌ, ์ฅ๋จ์ , ์ค์ ํ์ฉ ๋ฐ ์ต์ ํ ๋ฐฉ๋ฒ์ ๋น๊ต ๋ถ์ํด๋๋ ค์.
- ๋จ์ด: 1,460๊ฐ17๋ถ
[๐ค] React Context API์ Zustand: ์ ์ญ ์ํ ๊ด๋ฆฌ, ์ธ์ ๋ฌด์์ ์จ์ผ ํ ๊น์?
React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ์ญ ์ํ ๊ด๋ฆฌ๋ฅผ ๊ณ ๋ฏผํ๊ณ ๊ณ์ ๊ฐ์? Context API์ ๊ฐ๋ฒผ์ด ์ธ๋ถ ์ํ ๊ด๋ฆฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ Zustand๋ฅผ ๋น๊ต ๋ถ์ํ๊ณ , ์ค๋ฌด์์ ๊ฐ ๋๊ตฌ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ํ์ฉํ๋ ์ ๋ต์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์์ธํ ์๋ ค๋๋ ค์.
- ๋จ์ด: 2,004๊ฐ24๋ถ
[๐ค] Turborepo๋ก Next.js ๋ชจ๋ ธ๋ ํฌ ๊ตฌ์ถ: ํจ์จ์ ์ธ ๊ฐ๋ฐ ๋ฐ ์ต์ ํ ์ ๋ต
Turborepo๋ฅผ ํ์ฉํ์ฌ Next.js ํ๋ก์ ํธ๋ฅผ ๋ชจ๋ ธ๋ ํฌ๋ก ๊ตฌ์ฑํ๊ณ , ๊ณต์ ์ปดํฌ๋ํธ, ์ ํธ๋ฆฌํฐ, CI/CD ์ต์ ํ ๋ฐฉ์์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์ค๋ช ํด ๋๋ ค์.
- ๋จ์ด: 2,318๊ฐ27๋ถ
[๐ค] React useEffect ํ , ์ด์ ํท๊ฐ๋ฆฌ์ง ๋ง์ธ์! (์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ์๋ฒฝ ๊ฐ์ด๋)
React ๊ฐ๋ฐ์์ ํ์์ ์ธ useEffect ํ ์ ๋์ ์๋ฆฌ๋ถํฐ ์์กด์ฑ ๋ฐฐ์ด, ํด๋ฆฐ์ ํจ์ ํ์ฉ๋ฒ, ๊ทธ๋ฆฌ๊ณ ์ค๋ฌด์์ ์์ฃผ ๊ฒช๋ ์ค์์ ์ต์ ํ ์ ๋ต๊น์ง, ์ด์ค๊ธ ๊ฐ๋ฐ์๋ฅผ ์ํ ์๋ฒฝ ๊ฐ์ด๋๋ฅผ ์ ๊ณตํด์.
- ๋จ์ด: 3,270๊ฐ31๋ถ
[๐ค] Next.js Server Actions ์ค์ : ์๋ฌ ์ฒ๋ฆฌ, ์ ํจ์ฑ ๊ฒ์ฌ, ๋๊ด์ UI ์ ๋ฐ์ดํธ
Next.js Server Actions๋ฅผ ์ค๋ฌด์ ์ ์ฉํ ๋ ๋ง์ฃผํ๋ ์๋ฌ ์ฒ๋ฆฌ, ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ, ๊ทธ๋ฆฌ๊ณ ์ฌ์ฉ์ ๊ฒฝํ์ ํฅ์์ํค๋ ๋๊ด์ UI ์ ๋ฐ์ดํธ ๊ธฐ๋ฒ์ ์์ธํ ์ฝ๋ ์์์ ํจ๊ป ์์๋ณด์ธ์.
๋จ์ด: 1,981๊ฐ21๋ถ[๐ค] TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์๋ฒฝ ๊ฐ์ด๋: ์ค์ ํ์ฉ ํจํด
TypeScript ์ ํธ๋ฆฌํฐ ํ์ ์ ํต์ฌ ๊ฐ๋ ๊ณผ ์ค์ ํ์ฉ๋ฒ์ ๊น์ด ์๊ฒ ๋ค๋ค์. Pick, Omit, Partial, Required ๋ฑ ์์ฃผ ์ฐ๋ ์ ํธ๋ฆฌํฐ ํ์ ์ผ๋ก ๋ณต์กํ ํ์ ์ ํจ๊ณผ์ ์ผ๋ก ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์. ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์์ ์ฑ์ ๋์ด๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํด์.
- ๋จ์ด: 1,707๊ฐ20๋ถ
[๐ค] Next.js App Router ๋ฏธ๋ค์จ์ด: ๊ฐ๋ ฅํ ์์ฒญ ์ฒ๋ฆฌ ์ ๋ต๊ณผ ์ค์ ์์
Next.js App Router ํ๊ฒฝ์์ ๋ฏธ๋ค์จ์ด๋ฅผ ํ์ฉํด ์ฌ์ฉ์ ์ธ์ฆ, ๋ฆฌ๋ค์ด๋ ์ , ๊ตญ์ ํ ๋ฑ์ ์์ฒญ ์ฒ๋ฆฌ ๋ก์ง์ ํจ์จ์ ์ผ๋ก ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ค์ ์์ ์ ํจ๊ป ์์ธํ ์์๋ณด์ธ์.
- ๋จ์ด: 1,625๊ฐ19๋ถ
[๐ค] ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ ์ฌํ: ์ค์ฉ์ ์ธ ํจํด๊ณผ ํํ ์คํด๋ค
ํ์ ์คํฌ๋ฆฝํธ ์ ๋ค๋ฆญ(Generics)์ ๊น์ด ์ดํดํ๊ณ , ์ค๋ฌด์์ ์์ฃผ ์ฌ์ฉ๋๋ ์ ๋ค๋ฆญ ํจํด๊ณผ ํํ ๊ฒช๋ ์คํด๋ค์ ์ค์ ์ฝ๋ ์์์ ํจ๊ป ์ฝ๊ณ ๋ช ํํ๊ฒ ์ค๋ช ํด ๋๋ ค์. ํ์ ์์ ์ฑ๊ณผ ์ฝ๋ ์ฌ์ฌ์ฉ์ฑ์ ๋์ด๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.
๋จ์ด: 1,846๊ฐ18๋ถ[๐ค] Next.js Route Handler: App Router์์ ์์ ํ๊ณ ํจ์จ์ ์ธ API ๊ตฌ์ถํ๊ธฐ (์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ ํฌํจ)
Next.js App Router์ Route Handler๋ฅผ ์ฌ์ฉํ์ฌ API ์๋ํฌ์ธํธ๋ฅผ ๊ตฌ์ถํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ์์๋ด์. ์ธ์ฆ, ์๋ฌ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ์บ์ฑ ์ ๋ต์ ํฌํจํ ์ค์ฉ์ ์ธ ํ์ผ๋ก ์์ ํ๊ณ ํจ์จ์ ์ธ ์๋ฒ๋ฆฌ์ค ํจ์๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ตํ๋ด์.
- ๋จ์ด: 1,932๊ฐ22๋ถ
[๐ค] Next.js Image ์ปดํฌ๋ํธ ์ต์ ํ: Core Web Vitals ๊ฐ์ ๋ถํฐ ์ค์ ํ์ฉ๊น์ง
Next.js์ Image ์ปดํฌ๋ํธ๋ฅผ ํ์ฉํ์ฌ ์น ์ฑ๋ฅ ํต์ฌ ์งํ์ธ Core Web Vitals๋ฅผ ๊ฐ์ ํ๊ณ , ๋ค์ํ ์ต์ ํ ์ต์ ์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ธ๋ฃจ๊ฐ ์์ธํ ์๋ ค๋๋ ค์.
- ๋จ์ด: 2,173๊ฐ25๋ถ
[๐ค] Next.js 14.1+์ ํ์ : Partial Prerendering (PPR) ์๋ฒฝ ๊ฐ์ด๋์ ์ค์ ์ต์ ํ ์ ๋ต
Next.js 14.1๋ถํฐ ๋์ ๋ Partial Prerendering (PPR)์ ํตํด ์ด๊ธฐ ๋ก๋ฉ ์๋๋ฅผ ๊ทน๋ํํ๊ณ ๋์ ์ฝํ ์ธ ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ฃจ์ด์. PPR์ ๋์ ์๋ฆฌ๋ถํฐ ์ค์ ํ๋ก์ ํธ ์ ์ฉ ์ ๋ต๊น์ง, ๊ฐ๋ฐ์๋ค์ด ๊ถ๊ธํดํ๋ ๋ชจ๋ ๊ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,786๊ฐ19๋ถ
[๐ค] TypeScript ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋: ๋ณต์กํ ํ์ ๋ ์์ฝ๊ฒ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ
TypeScript ๊ฐ๋ฐ์์ ๋ง์ฃผํ๋ ๋ณต์กํ ํ์ ์ถ๋ก ๋ฌธ์ , ์กฐ๊ฑด๋ถ ํ์ ๊ณผ infer ํค์๋๋ฅผ ํ์ฉํ๋ฉด ํจ์ฌ ์ฐ์ํ๊ณ ๊ฐ๋ ฅํ๊ฒ ํด๊ฒฐํ ์ ์์ด์. ์ค์ ์์ ์ ํจ๊ป ๊ทธ ํ์ฉ๋ฒ์ ์ฌ๋ ์๊ฒ ๋ค๋ค๋ด ๋๋ค.
- ๋จ์ด: 1,697๊ฐ21๋ถ
[๐ค] JavaScript ์ด๋ฒคํธ ๋ฃจํ(Event Loop) ์์ ์ ๋ณต: ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ฐํ์ ๋์ ์๋ฆฌ
JavaScript์ ํต์ฌ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฉ์ปค๋์ฆ์ธ ์ด๋ฒคํธ ๋ฃจํ์ ๋์ ์๋ฆฌ๋ฅผ ์ฌ๋ ์๊ฒ ํํค์ณ ๋ด์. ์ฝ ์คํ, ํ์คํฌ ํ, ๋ง์ดํฌ๋กํ์คํฌ ํ์์ ์ํธ์์ฉ์ ์ดํดํ๊ณ , ์ค๋ฌด์์ ๋ง์ฃผ์น๋ ๋น๋๊ธฐ ์ฝ๋์ ๋์์ ๋ช ํํ ์์ธกํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ ค์.
- ๋จ์ด: 1,960๊ฐ23๋ถ
[๐ค] Next.js Server & Client Components, ์ค์ ์์ ํ๋ช ํ๊ฒ ์ ํํ๋ ๊ฐ์ด๋
Next.js App Router์์ Server Components์ Client Components ์ค ์ด๋ค ๊ฒ์ ์ฌ์ฉํด์ผ ํ ์ง ๊ณ ๋ฏผ์ด์ ๊ฐ์? ์ด ๊ธ์์ ๋ ์ปดํฌ๋ํธ์ ํต์ฌ ์ฐจ์ด์ , ์ฌ์ฉ ์์ , ๊ทธ๋ฆฌ๊ณ ์ฑ๋ฅ ์ต์ ํ๋ฅผ ์ํ ์ค์ ์ ๋ต์ ๋ธ๋ฃจ๊ฐ ์๋ ค๋๋ฆด๊ฒ์.
- ๋จ์ด: 1,878๊ฐ21๋ถ
[๐ค] TypeScript satisfies ์ฐ์ฐ์: ํ์ ์ถ๋ก ๊ณผ ์์ ์ฑ์ ๋์์ ์ก๋ ๋น๋ฒ
TypeScript์ `satisfies` ์ฐ์ฐ์๋ฅผ ํ์ฉํ์ฌ ํ์ ์ถ๋ก ์ ์ ์ฐ์ฑ์ ์ ์งํ๋ฉด์๋ ์๊ฒฉํ ํ์ ์์ ์ฑ์ ํ๋ณดํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์. ์ค์ฉ์ ์ธ ์์๋ฅผ ํตํด ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ๋ ธํ์ฐ๋ฅผ ๊ณต์ ํฉ๋๋ค.
- ๋จ์ด: 1,207๊ฐ15๋ถ
[๐ค] React 19 ์๋ก์ด ๊ธฐ๋ฅ: use ํ , Actions, ๊ทธ๋ฆฌ๊ณ ์ปดํ์ผ๋ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ
React 19์ ํต์ฌ ๋ณ๊ฒฝ ์ฌํญ์ธ use ํ , ์๋ฒ ์ก์ , ๊ทธ๋ฆฌ๊ณ React ์ปดํ์ผ๋ฌ์ ๋์ ๋ฐฐ๊ฒฝ๊ณผ ์ค์ ํ์ฉ ์์๋ฅผ ์ด์ค๊ธ ๊ฐ๋ฐ์ ๋๋์ด์ ๋ง์ถฐ ์์ธํ ์ค๋ช ํฉ๋๋ค. ์ต์ React ์ ๋ฐ์ดํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์ ์ฑ๋ฅ๊ณผ ๊ฐ๋ฐ ๊ฒฝํ์ ํฅ์์ํค๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.
- ๋จ์ด: 1,512๊ฐ16๋ถ
[๐ค] Next.js App Router ์บ์ฑ ์ ๋ต: ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ (revalidatePath, revalidateTag) ์๋ฒฝ ๊ฐ์ด๋
Next.js 14 App Router์์ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์บ์ฑ ์ ๋ต๊ณผ revalidatePath, revalidateTag๋ฅผ ์ด์ฉํ ๋ฐ์ดํฐ ์ฌ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ์ค๋ฌด ์์์ ํจ๊ป ์์ธํ ์์๋ณด๊ณ ์น ์ฑ๋ฅ์ ์ต์ ํํ๋ ๋ฐฉ๋ฒ์ ๋ฐฐ์๋ณด์ธ์.