elice/WIL

[week_08] React ๊ธฐ์ดˆ โ…ก(2) Hooks

1. Hook

Hook์€ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌ(State)ํ•˜๊ณ , ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์ƒํ˜ธ์ž‘์šฉ(Effect)์„ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ์•ž์„œ ํ•™์Šตํ•œ useState๊ฐ€ ๋ฐ”๋กœ State Hook์ด๋‹ค. Hook์€ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ(Class Component)๋ฅผ ๋ณด์™„ํ•˜๊ณ , ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด React 16.8 ๋ฒ„์ „์—์„œ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

โœจ Hook ์œ ์˜์‚ฌํ•ญ

1) Hook์€ Reactํ•จ์ˆ˜(์ปดํฌ๋„ŒํŠธ, Hook) ๋‚ด์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค.
2) Hook์˜ ์ด๋ฆ„์€ ๋ฐ˜๋“œ์‹œ 'use'๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค.
3) ์ตœ์ƒ์œ„ Level์—์„œ๋งŒ Hook์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ์ปดํฌ๋„ŒํŠธ ๋‚ด์—์„œ Hook์„ ์‚ฌ์šฉํ•  ๋•Œ ๋ฐ˜๋“œ์‹œ ์ฒซ๋ฒˆ์งธ ์ค‘๊ด„ํ˜ธ({ }) ์•ˆ์—์„œ๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. (๐Ÿ‘‰ if๋ฌธ, for๋ฌธ ์•ˆ์ชฝ ๋˜๋Š” ์ฝœ๋ฐฑํ•จ์ˆ˜ ๋‚ด์—์„œ ํ˜ธ์ถœํ•˜๋ฉด ์•ˆ๋œ๋‹ค.)

 

2. State Hook๊ณผ Effect Hook

2-1. State Hook

const App = () => {
	// ์ผ๋ฐ˜์ ์ธ useState ์‚ฌ์šฉ๋ฒ•
	const [state์ด๋ฆ„, setState์ด๋ฆ„] = useState(์ดˆ๊ธฐ๊ฐ’)
}
  • useState๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด ๋™์ ์ธ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” hook์ด๋‹ค.
  • ์ตœ์ดˆ์— useState๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์ดˆ๊ธฐ๊ฐ’์œผ๋กœ ์„ค์ •๋˜๋ฉฐ, ์ดํ›„ ์žฌ ๋ Œ๋”๋ง์ด ๋  ๊ฒฝ์šฐ ์ด ๊ฐ’์€ ๋ฌด์‹œ๋œ๋‹ค.
  • state๋Š” ์ฝ๊ธฐ ์ „์šฉ์ด๋ฏ€๋กœ ์ง์ ‘ ์ˆ˜์ •ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
  • state๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” setState๋ฅผ ์ด์šฉํ•œ๋‹ค.
  • state๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์ž๋™์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ ๋ Œ๋”๋ง๋œ๋‹ค.
const App = () => {
	const [title, setTitle] = useState("");
    
    setTitle("Hello"); // State๋ฅผ ๋ณ€๊ฒฝํ•  ๊ฐ’์„ ์ง์ ‘ ์ž…๋ ฅ
    
    setTitle((current) => { // ๋˜๋Š” ํ˜„์žฌ ๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜ ์„ ์–ธ
    	return current + "World"; // return ๊ฐ’์ด state์— ๋ฐ˜์˜๋œ๋‹ค.
    });
}
  • state๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” setState ํ•จ์ˆ˜์— ์ง์ ‘ ๊ฐ’์„ ์ž…๋ ฅํ•˜๊ฑฐ๋‚˜,
  • ํ˜„์žฌ ๊ฐ’์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š” ํ•จ์ˆ˜๋ฅผ ์ „๋‹ฌํ•œ๋‹ค. ์ด ๋•Œ ํ•จ์ˆ˜์—์„œ return๋˜๋Š” ๊ฐ’์ด state์— ๋ฐ˜์˜๋œ๋‹ค.

2-2. Effect Hook

const App = () => {
	useEffect(EffectCallback, [Deps])
}
  • Effect Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ side effect๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ฆ‰, ์–ด๋– ํ•œ ๊ฐ’์ด ๋ณ€ํ•  ๋•Œ ๋งˆ๋‹ค ๋‚ด๊ฐ€ ์„ค์ •ํ•œ ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ตœ์ดˆ๋กœ ๋ Œ๋”๋ง๋  ๋•Œ, ์ง€์ •ํ•œ State๋‚˜ Props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค EffectCallbackํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
  • Deps: ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ๋ณ€์ˆ˜๋“ค์˜ ์ง‘ํ•ฉ(๋ฐฐ์—ด)
  • EffectCallback: Deps์— ์ง€์ •๋œ ๋ฒผ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ์‹คํ–‰ํ•  ํ•จ์ˆ˜
const App = () => {
	const [count, setCount] = useState(0);
    
    useEffect(() => {
    	console.log(`๋ฒ„ํŠผ์„ ${count}ํšŒ ํด๋ฆญํ–ˆ์Šต๋‹ˆ๋‹ค.`);
    }, [count]); // count์˜ state๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ ๋งˆ๋‹ค ์ฒซ ๋ฒˆ์งธ ์ธ์ž์˜ ํ•จ์ˆ˜ ์‹คํ–‰
    
    return (
    	<div>
        	<button onClick={() => setCount(count+1)}>
            	ํด๋ฆญํ•˜์„ธ์š”
            </button>
        </div>
    );
}

 

  • Effect Hook์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜ ์ปดํฌ๋„ŒํŠธ์—์„œ side effect๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ตœ์ดˆ๋กœ ๋ Œ๋”๋ง๋  ๋•Œ, ์ง€์ •ํ•œ State๋‚˜ Prop๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ดํŽ™ํŠธ ์ฝœ๋ฐฑ ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋œ๋‹ค.
const App = () => {
	useEffect(() => {
    	// State๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ, ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ
    	const intervalId = setInterval(() => {
        	console.log('Hi');
        }, 1000);
        
        // ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ ๋ Œ๋”๋ง ํ•˜๊ธฐ ์ „์—, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—†์–ด์งˆ ๋•Œ
        return () => {
        	clearInterval(intervalId);
        }
    }, []); // ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์ตœ์ดˆ๋กœ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰๋œ๋‹ค.
}
  • useEffect์˜ ์ดํŽ™ํŠธ ํ•จ์ˆ˜ ๋‚ด์—์„œ ๋‹ค๋ฅธ ํ•จ์ˆ˜๋ฅผ returnํ•  ๊ฒฝ์šฐ state๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋‹ค์‹œ ๋ Œ๋”๋ง๋˜๊ธฐ ์ „๊ณผ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์—†์–ด์งˆ ๋•Œ(Destroy) ํ˜ธ์ถœํ•  ํ•จ์ˆ˜๋ฅผ ์ง€์ •ํ•˜๊ฒŒ ๋œ๋‹ค.

 

3. ์ด์™ธ์˜ Hooks

3-1. useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b])
  • ์ง€์ •ํ•œ State๋‚˜ Props๊ฐ€ ๋ณ€๊ฒฝ๋  ๊ฒฝ์šฐ ํ•ด๋‹น ๊ฐ’์„ ํ™œ์šฉํ•ด ๊ณ„์‚ฐ๋œ ๊ฐ’์„ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ ์žฌ๋ Œ๋”๋ง ์‹œ ๋ถˆํŽผ์š”ํ•œ ์—ฐ์‚ฐ์„ ์ค„์ธ๋‹ค.
  • useMemon์˜ ์—ฐ์‚ฐ์€ ๋ Œ๋”๋ง ๋‹จ๊ณ„์—์„œ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๋กœ์ง์„ ์ž‘์„ฑํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋œ๋‹ค.
const App = () => {
	const [firstName, setFirstName] = useState('์ฒ ์ˆ˜')
    const [lastName, setLastName] = useState('๊น€')
    
    // ์ด๋ฆ„๊ณผ ์„ฑ์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ํ’€๋„ค์ž„์„ ๋ฉ”๋ชจํ•ด๋‘”๋‹ค.
    const fullName = useMemo(() => {
    	return `${firstName} ${lastName}` // ๋ฆฌํ„ด๋˜๋Š” ๊ฐ’์ด fullName์— ๋“ค์–ด๊ฐ„๋‹ค.
    }, [firstName, lastName])
}

 

3-2. useCallback

const memoizedCallback = useCallback (
	() => {
    	doSomething(a, b);
    },
    [a, b]
);
  • ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” Hook์ด๋‹ค. ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋  ๋•Œ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
  • useMemo๊ฐ€ ๋ณ€์ˆ˜๋ฅผ ๋ฉ”๋ชจํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” Hook์ด๋ผ๋ฉด, useCallback์€ ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจํ•˜๊ธฐ ์œ„ํ•ด ์กด์žฌํ•˜๋Š” Hook์ด๋‹ค.
  • useMemo(() => fn, deps) ์™€ useCallback(fn, deps) ๋Š” ๊ฐ™๋‹ค.
const App = () => {
	const [firstName, setFirstName] = useState('์ฒ ์ˆ˜')
    const [lastName, setLastName] = useState('๊น€')
    
    // ์ด๋ฆ„๊ณผ ์„ฑ์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ํ’€๋„ค์ž„์„ ๋ฆฌํ„ดํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ
    const getFullName = useCallback(() => {
    	return `${firstName} ${lastName}`
    }, [firstName, lastName]) // ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.
    
    return <>{getFullName()}</> // ํ•จ์ˆ˜์˜ ํ˜•ํƒœ๋กœ ์‚ฌ์šฉ
}

 

3-3. useRef

const refContainer = useRef(initialValue);
  • ์ปดํฌ๋„ŒํŠธ ์ƒ์•  ์ฃผ๊ธฐ(์ƒ๋ช… ์ฃผ๊ธฐ) ๋‚ด์—์„œ ์œ ์ง€ํ•  ref ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ref ๊ฐ์ฒด๋Š” .current ๋ผ๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ด ๊ฐ’์„ ์ž์œ ๋กญ๊ฒŒ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ React์—์„œ DOM Element์— ์ ‘๊ทผํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (DOM Element์˜ ref ์†์„ฑ์„ ์ด์šฉ)
  • useRef์— ์˜ํ•ด ๋ฐ˜ํ™˜๋œ ref ๊ฐ์ฒด๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด๋„ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š๋Š”๋‹ค.
const App = () => {
	const inputRef = useRef(null)
    const onButtonClick = () => {
    	inputRef.current.focus()
    }
    return (
    	<div>
        	<input ref={inputRef} type="text" />
            <button onClick={onButtonClick}>input์œผ๋กœ ํฌ์ปค์Šค</button>
        </div>
    )
}

 

4. Custom Hook

์ž์‹ ๋งŒ์˜ Hook์„ ๋งŒ๋“ค๋ฉด ์ปดํฌ๋„ŒํŠธ ๋กœ์ง์„ ํ•จ์ˆ˜๋กœ ๋ฝ‘์•„๋‚ด์–ด ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. UI ์š”์†Œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ๋กœ์ง์˜ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด์„œ๋Š” Custom Hook์„ ์ œ์ž‘ํ•œ๋‹ค.

function useMyHook(args) {
	const [status, setStatus] = useState(null);
    // ...
    return status;
}
  • ํ•œ ๋กœ์ง์ด ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉ๋  ๊ฒฝ์šฐ ํ•จ์ˆ˜๋ฅผ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ ์ฒ˜๋Ÿผ Hook์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ผ ๋ฟ, ์ƒˆ๋กœ์šด ๊ฐœ๋…์€ ์•„๋‹ˆ๋‹ค.
  • Hook์˜ ์ด๋ฆ„์€ 'use'๋กœ ์‹œ์ž‘ํ•ด์•ผํ•œ๋‹ค.
  • ํ•œ Hook ๋‚ด์˜ state๋Š” ๊ณต์œ ๋˜์ง€ ์•Š๋Š”๋‹ค.