๐Ÿ“ซ

useCallback

ย 
ย 

7.1 useCallback์ด๋ž€?

ย 
useCallback์€ useMemo์™€ ๊ฐ™์ด ์ปดํฌ๋„ŒํŠธ์˜ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•˜์—ฌ ์‚ฌ์šฉ๋˜๋Š” Hook์ž…๋‹ˆ๋‹ค. useCallback์€ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์žฌ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
ย 

7.1.1 ๊ธฐ๋ณธ ๊ตฌ์กฐ

ย 
const memoizedCallback = useCallback(() => {doSomething(a, b)},[a, b]);
ย 
useCallback์€ ์œ„์™€ ๊ฐ™์ด ๋‘ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•  ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ, ๋‘๋ฒˆ์งธ ์ธ์ž๋Š” useEffect, useMemo์™€ ๊ฐ™์ด ์˜์กด์„ฑ ๋ฐฐ์—ด์ด ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค. useCallback์€ ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋œ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์ด ์ฝœ๋ฐฑํ•จ์ˆ˜๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๊ฒฝ์šฐ์—๋งŒ ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์˜์กด์„ฑ ๋ฐฐ์—ด์˜ ๊ฐ’์ด ๋™์ผํ•˜๋‹ค๋ฉด, ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๋”๋ผ๋„ ์ƒˆ๋กœ์šด ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š๊ณ  ๊ธฐ์กด ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
ย 

7.1.2 useMemo์™€์˜ ๋น„๊ต

ย 
useCallback์„ useMemo๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ‘œํ˜„ํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
ย 
const memoizedCallback = useCallback(function, deps); const memoizedValue = useMemo(() => function, deps);
ย 
์œ„์˜ ๋‘ ์ฝ”๋“œ๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค. useCallback์€ useMemo๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. useCallback์€ useMemo์—์„œ ๊ฐ’์ด ์•„๋‹Œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์— ํŽธ์˜์„ฑ์„ ์ฆ์ง„์‹œํ‚จ Hook์ž…๋‹ˆ๋‹ค. ๋‘ Hook์€ ์„ฑ๋Šฅ ์ตœ์ ํ™”๋ผ๋Š” ๋ชฉ์ ์—์„œ๋Š” ๊ณตํ†ต์ ์„ ๊ฐ–์ง€๋งŒ, ํŠน์ • ๊ฐ’์„ ์žฌ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€ ํ˜น์€ ํŠน์ • ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•  ๊ฒƒ์ธ์ง€์— ๋”ฐ๋ผ ์„ ํƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. useMemo๋Š” ๊ฐ’์˜ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์ „๋‹ฌ๋œ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์ง€๋งŒ, useCallback์€ ํ•จ์ˆ˜์˜ ์žฌ์‚ฌ์šฉ์„ ์œ„ํ•ด ์ „๋‹ฌ๋œ ํ•จ์ˆ˜ ์ž์ฒด๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•ฉ๋‹ˆ๋‹ค.
ย 

ย 

7.2 useCallback์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

ย 
useCallback์„ ์‚ฌ์šฉํ•˜๋ฉด ๋งค๋ฒˆ ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๊ธฐ์–ตํ•˜๊ฒŒ ํ•ด๋‘์—ˆ๋‹ค๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ํ•จ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋ฉ”๋ชจ๋ฆฌ๋‚˜ CPU์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŽ์ด ์ฐจ์ง€ํ•˜๋Š” ์ž‘์—…์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ props๊ฐ€ ๋ฐ”๋€Œ์ง€ ์•Š์•˜์„ ๋•Œ, React์˜ ๊ฐ€์ƒ ๋”(Virtual DOM)์— ๋ฆฌ๋ Œ๋”๋ง์„ ํ•˜์ง€ ์•Š๊ณ  ์ด์ „ ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ Œ๋”๋ง ์‹œ๊ฐ„์„ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
useCallback์ด ์‚ฌ์šฉ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•  ๋•Œ, ๋‘ ๋ฒˆ์งธ๋Š” ์ฐธ์กฐ ๋™์ผ์„ฑ์ด ์œ ์ง€๋˜์ง€ ์•Š์•„ ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๋•Œ์ž…๋‹ˆ๋‹ค.
ย 

7.2.1 useCallback์œผ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ

ย 
๊ธฐ๋ณธ์ ์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ state๋‚˜ proprs๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๋ฐ›๋Š” input ํƒœ๊ทธ๊ฐ™์ด ์—…๋ฐ์ดํŠธ๊ฐ€ ์žฆ์€ state๊ฐ€ ์žˆ๋Š” ์ปดํฌ๋„ŒํŠธ๋ผ๋ฉด ๋งค๋ฒˆ ์ƒˆ๋กญ๊ฒŒ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
ย 
import React, { useState } from "react"; function InputId() { const [id, setId] = useState(""); const onChangeId = (e) => { setId(e.target.value); }; return <input onChange={onChangeId} />; } export default InputId;
์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋ณตํ•ด์„œ ์ƒ์„ฑ๋˜๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ํ•จ์ˆ˜๋ฅผ useCallback์œผ๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ํ•˜์—ฌ, ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋”๋ผ๋„ ์˜์กดํ•˜๋Š” ๊ฐ’๋“ค์ด ๋ฐ”๋€Œ์ง€ ์•Š๋Š” ํ•œ ๊ธฐ์กด ํ•จ์ˆ˜๋ฅผ ๊ณ„์†ํ•ด์„œ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
ย 
import React, { useCallback, useState } from "react"; function InputId() { const [id, setId] = useState(""); // useCallback ์‚ฌ์šฉ const onChangeId = useCallback( e => { setId(e.target.value); }, []); return <input onChange={onChangeId} />; } export default InputId;
ย 

7.2.2 useCallback์œผ๋กœ ์ฐธ์กฐ ๋™์ผ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

ย 
useEffect ์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด, ํ•จ์ˆ˜๋„ ๊ฐ์ฒด ํƒ€์ž…์ด๊ธฐ ๋•Œ๋ฌธ์— ์ฑ•ํ„ฐ6(์‹ค์Šต2)์—์„œ ๋ดค๋˜ ์ฐธ์กฐ ๋™์ผ์„ฑ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•ž์—์„œ๋Š” ๊ฐ’์„ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ useMemo๋ฅผ ํ†ตํ•ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ–ˆ๋‹ค๋ฉด ์ด๋ฒˆ์—๋Š” ํ•จ์ˆ˜๋ฅผ ์žฌ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋ฏ€๋กœ useCallback์„ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
import React, { useState, useEffect } from "react"; function UserProfile({ id }) { const [user, setUser] = useState(null); const fetchUserInfo = () => fetch(`https://user-api.com/users/${Id}`) .then((response) => response.json()) .then(({ user }) => user); useEffect(() => { fetchUserInfo().then((user) => setUser(user)); }, [fetchUserInfo]); ... }
ย 
์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด , useEffect์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— fetchUserInfo ํ•จ์ˆ˜๊ฐ€ ๋“ค์–ด์žˆ์œผ๋ฏ€๋กœ fetchUserInfo๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ API๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ฐ์ฒด ํƒ€์ž…์ธ fetchUserInfo๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง๋˜๋ฉด ์ƒˆ๋กœ์šด ์ฐธ์กฐ ๊ฐ’์œผ๋กœ ๋ณ€๊ฒฝ๋ฉ๋‹ˆ๋‹ค. fetchUserInfo ์˜ ์ฐธ์กฐ ๊ฐ’์ด ๋ณ€๊ฒฝ๋˜๋ฉด useEffect๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰๋˜๊ณ , state์ธ user ๊ฐ’์ด ์—…๋ฐ์ดํŠธ๋˜์–ด ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ useCallback์œผ๋กœ ํ•ด๊ฒฐํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
import React, { useState, useEffect, useCallback } from "react"; function UserProfile({ id }) { const [user, setUser] = useState(null); // useCallback์„ ์‚ฌ์šฉํ•œ ์˜ˆ์ œ const fetchUserInfo = useCallback( () => fetch(`https://user-api.com/users/${id}`) .then((response) => response.json()) .then(({ user }) => user), [id] ); useEffect(() => { fetchUserInfo().then((user) => setUser(user)); }, [fetchUserInfo]); ... }
ย 
useCallback์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ์ฃผ๋ฉด ํ•ด๋‹น ํ•จ์ˆ˜๋Š” ์ด๋ฏธ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜์กด์„ฑ ๋ฐฐ์—ด๋กœ ๋„ฃ์–ด์ค€ id๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š๋Š” ํ•œ ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ย 

ย 

7.3. (์‹ค์Šต1) useCallback ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

ย 
useCallback์˜ ์‚ฌ์šฉ๋ฒ•๊ณผ ์‚ฌ์šฉ์‹œ๊ธฐ๋ฅผ ํ™•์ธํ•ด๋ณด๊ณ ์ž ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋ฅผ ํ†ตํ•ด useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ์™€ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ๋ฅผ ๋น„๊ตํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•ด๋‹น ์˜ˆ์ œ์—์„œ๋Š” ํ† ๊ธ€ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜์—ฌ bool ๊ฐ’์— ๋”ฐ๋ผ ๋ผ์ด์บฃ์˜ ์™ธ์ถœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝ์‹œํ‚ค๋Š”๋ฐ, ์ƒํƒœ๊ฐ’์ด true์ผ ๊ฒฝ์šฐ โ€˜์ง‘์—์žˆ์–ด์š”!โ€™, false์ผ ๊ฒฝ์šฐ โ€˜์™ธ์ถœํ–ˆ์–ด์š”!โ€™๋ผ๋Š” ๋ฌธ๊ตฌ์™€ ์ด๋ฏธ์ง€๋กœ ์‰ฝ๊ฒŒ ๋ผ์ด์บฃ์˜ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

7.3.1 useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ

ย 
import { useState, useEffect, useCallback } from "react"; import goLicat from "./go.jpg"; import backLicat from "./back.jpg"; function App() { const [locationToggle, setLocationToggle] = useState(false); const licatLocation = () => { console.log( locationToggle ? "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ true(์ง‘์—์žˆ์–ด์š”!)" : "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ false(์™ธ์ถœํ–ˆ์–ด์š”!)" ); return; }; useEffect(() => { console.log("licatLocation ํ•จ์ˆ˜ ํ˜ธ์ถœ!"); }, [licatLocation]); return ( <> <h2>๐Ÿ“ ๋ผ์ด์บฃ ์ง€๊ธˆ ์ง‘์— ์žˆ๋‚˜์š”?</h2> <div> {locationToggle ? ( <img src={backLicat} alt="์ง‘์— ๋“ค์–ด๊ฐ„ ๋ผ์ด์บฃ" /> ) : ( <img src={goLicat} alt="์™ธ์ถœํ•œ ๋ผ์ด์บฃ" /> )} </div> <h3> ๋ผ์ด์บฃ์€ ์ง€๊ธˆ {locationToggle ? " '์ง‘์—์žˆ์–ด์š”!'" : " '์™ธ์ถœํ–ˆ์–ด์š”!'"} </h3> <button onClick={() => setLocationToggle(!locationToggle)} style={{ margin: "-5px 10px 0 0", fontSize: "14px", }} > ๐Ÿฆ ๋ผ์ด์บฃ ์ด๋™! </button> <button onClick={licatLocation} style={{ fontSize: "14px" }}> ๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’ </button> </> ); } export default App;
App.jsx
ย 
์œ„ ์˜ˆ์ œ๋Š” ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค locationToggle ๋ณ€์ˆ˜์— ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ๋ฐ˜์˜ํ•ด์ฃผ๊ณ , ํ˜„์žฌ getLocation๊ฐ’ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ licatLocation ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ฝ˜์†”์— ์ƒํƒœ ๊ฐ’์„ ์ถœ๋ ฅํ•ด์ค๋‹ˆ๋‹ค. ๋งŒ์•ฝ ์ƒํ™ฉ์— ๋”ฐ๋ผ licatLocation ํ•จ์ˆ˜์— ๋ณ€ํ™”๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์‹คํ–‰๋˜๋Š” useEffect๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด, ์–ด๋–ค ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„๊นŒ์š”?
ย 
notion imagenotion image
ย 
์ฒ˜์Œ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๋ฉด, useEffect๊ฐ€ ๋งˆ์šดํŠธ๋ฉ๋‹ˆ๋‹ค. ์ฝ˜์†”์ฐฝ์— ๋ณด์ด๋Š” ๋ฉ”์„ธ์ง€๋Š” useEffect๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋ผ์ด์บฃ์˜ ์™ธ์ถœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
notion imagenotion image
ย 
๋ถ„๋ช… ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ๋งŒ ํด๋ฆญํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— licatLocation ํ•จ์ˆ˜์—๋Š” ์˜ํ–ฅ์ด ์—†์–ด licatLocation ํ•จ์ˆ˜๋ฅผ ์˜์กดํ•˜๋Š” useEffect๋„ ์‹คํ–‰๋˜์ง€ ์•Š์„ ๊ฑฐ๋ผ๊ณ  ์˜ˆ์ƒํ•˜๊ณ  ์žˆ์—ˆ์„ ๊ฒ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์™œ useEffect๋„ ๊ฐ™์ด ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ๊ฑธ๊นŒ์š”?
ย 
๊ทธ ๋‹ต์€ React ๋ฆฌ๋ Œ๋”๋ง ์กฐ๊ฑด ์ค‘ state ๊ฐ’์ด ๋ณ€ํ•˜๋ฉด ์ปดํฌ๋„ŒํŠธ ์ „์ฒด๊ฐ€ ๋ฆฌ๋ Œ๋”๋ง๋˜๊ณ , ํ•จ์ˆ˜๊ฐ€ ๋‹ค์‹œ ์ƒ์„ฑ๋˜์–ด ์ƒˆ๋กœ์šด ์ฃผ์†Œ ๊ฐ’์„ ์ฐธ์กฐํ•˜๋Š” ์ฐธ์กฐ ๋™์ผ์„ฑ ๋ฌธ์ œ๋ฅผ ํ†ตํ•ด ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ง€๊ธˆ ์˜ˆ์ œ์ฒ˜๋Ÿผ ๊ฐ„๋‹จํ•œ ์ƒํ™ฉ์—์„œ๋Š” ๋ฆฌ๋ Œ๋”๋ง์ด ๊ณ„์† ๋ฐœ์ƒํ•ด๋„ ์„ฑ๋Šฅ์— ํฌ๊ฒŒ ์˜ํ–ฅ์ด ์—†์ง€๋งŒ, ๋งŒ์•ฝ ํ˜ธ์ถœํ•˜๋Š” ํ•จ์ˆ˜๊ฐ€ ๋งค์šฐ ๋ฌด๊ฑฐ์šด ๋กœ์ง์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋ฉด ์ˆ˜์—†์ด ๋ฐ˜๋ณต๋˜๋Š” ๋ฆฌ๋ Œ๋”๋ง์€ ๋งค์šฐ ๋น„ํšจ์œจ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
ย 
์ด๋Ÿด ๋•Œ useCallback์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์žฌ์‚ฌ์šฉํ•  ํ•จ์ˆ˜๋ฅผ useCallback์˜ ์ฝœ๋ฐฑํ•จ์ˆ˜๋กœ ๋„ฃ์–ด ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ํ•ด์ฃผ๋ฉด, ์ด์ œ state ๊ฐ’์ด ๋ณ€ํ•ด๋„ licatLocation ํ•จ์ˆ˜์— ๋ณ€ํ™”๊ฐ€ ์—†์„ ๋• useEffect๋„ ์‹คํ–‰๋˜์ง€ ์•Š์•„ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
ย 

7.3.2 useCallback์„ ์‚ฌ์šฉํ•  ๋•Œ

const licatLocation = useCallback(() => { console.log( locationToggle ? "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ true(์ง‘์—์žˆ์–ด์š”!)" : "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ false(์™ธ์ถœํ–ˆ์–ด์š”!)" ); return; }, []); // ๋นˆ ๋ฐฐ์—ด์„ ๋„ฃ์—ˆ์„ ๋•Œ
ย 
โ—
useCallback ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 
notion imagenotion image
์‹คํ–‰ํ™”๋ฉด์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด useCallback์œผ๋กœ licatLocation ํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ์ค€ ๊ฒฐ๊ณผ useEffect๋Š” ๋” ์ด์ƒ ์‹คํ–‰๋˜์ง€ ์•Š์ง€๋งŒ, ํ˜„์žฌ locationToggle ์— ์ €์žฅ๋œ state ๊ฐ’์€ true์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  licatLocation ํ•จ์ˆ˜๋Š” ๊ณ„์†ํ•ด์„œ false ๊ฐ’์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์€ ์˜์กด์„ฑ ๋ฐฐ์—ด์„ ๋นˆ ๋ฐฐ์—ด๋กœ ์ฃผ๊ฒŒ ๋  ๋•Œ ๋งŒ๋‚  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜์กด์„ฑ ๋ฐฐ์—ด์— ์•„๋ฌด ์กฐ๊ฑด๋„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด, ์ฒ˜์Œ ๋ Œ๋”๋ง๋  ๋•Œ์˜ state ๊ฐ’์ด ๊ทธ๋Œ€๋กœ ๋ฉ”๋ชจ์ด์ œ์ด์…˜๋ฉ๋‹ˆ๋‹ค. ๋ฆฌ๋ Œ๋”๋ง์„ ํ•ด์ค„ ์กฐ๊ฑด์ด ์—†์–ด์„œ ๊ณ„์†์ฒ˜์Œ ์ €์žฅ๋œ ์ƒํƒœ ๊ทธ๋Œ€๋กœ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์œ„์˜ ์ƒํ™ฉ๋„ ์ฝœ๋ฐฑํ•จ์ˆ˜๊ฐ€ ๋ฉ”๋ชจ์ด์ œ์ด์…˜ ๋  ๋•Œ locationToggle ๊ฐ’์ด false๋กœ ์ €์žฅ๋œ ์ƒํ™ฉ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— useCallback์„ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ์˜์กด์„ฑ ๋ฐฐ์—ด์— ๋ฆฌ๋ Œ๋”๋ง์„ ์œ„ํ•œ ์กฐ๊ฑด์„ ๋ฐ˜๋“œ์‹œ ๋„ฃ์–ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ย 
๋ฆฌ๋ Œ๋”๋ง์„ ์œ„ํ•œ ์กฐ๊ฑด์ธ locationToggle ๊นŒ์ง€ ๋„ฃ์–ด์ฃผ๊ณ , ๋‹ค์‹œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ด…์‹œ๋‹ค.
ย 
const licatLocation = useCallback(() => { console.log( locationToggle ? "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ true(์ง‘์—์žˆ์–ด์š”!)" : "๐Ÿ“ ํ˜„์žฌ getLocation๊ฐ’์€ false(์™ธ์ถœํ–ˆ์–ด์š”!)" ); return; }, [locationToggle]); // ๊ฐ’์„ ๋„ฃ์—ˆ์„ ๋•Œ
ย 
notion imagenotion image
notion imagenotion image
ย 
์ฝ˜์†” ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด, ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ๋งˆ๋‹ค 'licatLocation ํ•จ์ˆ˜ ํ˜ธ์ถœ!' ๋ฉ”์„ธ์ง€๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ state ๊ฐ’์— ๋”ฐ๋ผ ์™ผ์ชฝ ํ™”๋ฉด์— ์ถœ๋ ฅ๋˜๋Š” state ๊ฐ’๊ณผ licatLocation ํ•จ์ˆ˜๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” state ๊ฐ’์ด ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

ย 

7.4. (์‹ค์Šต2) useCallback ์‚ฌ์šฉํ•ด๋ณด๊ธฐ

ย 
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋  ๋•Œ ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋„ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ props๊ฐ€ ๊ฐ™์€ ์ฃผ์†Œ์ผ ๊ฒฝ์šฐ, ์ฃผ์†Œ๋ฅผ ๋น„๊ตํ•˜๊ณ  ๋ฆฌ๋ Œ๋”๋งํ•˜๋Š” React.memo๋ฅผ ๊ฐ์‹ธ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์‹ค์Šต์—์„œ๋Š”, React.memo์™€ useCallback Hook์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์ด๋Š” ๊ฒƒ์— ๋ชฉ์ ์„ ๋‘์—ˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ์Šคํƒ€์ผ๋ง ์ฝ”๋“œ๋Š” ์ œ์™ธํ•˜๊ณ  ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. * 7.4.1 ์ตœ์ข… ์ฝ”๋“œ์— ์Šคํƒ€์ผ๋ง ์ฝ”๋“œ๊ฐ€ ๋ชจ๋‘ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ
์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ
// ----- (1) function App() { //useState const [yellowSay, setYellowSay] = useState(false); const [blueSay, setBlueSay] = useState(true); const [licatSize, setLicatSize] = useState(50); const toggleYellow = () => setYellowSay(!yellowSay); ----- (2) const toggleBlue = () => setBlueSay(!blueSay); const licatStyle = { width: `${licatSize}px`, height: `${licatSize}px`, }; // ๋ผ์ด์บฃ ์Šคํƒ€์ผ, ์ด๋ฏธ์ง€, useEffect๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” RealLicat ์ปดํฌ๋„ŒํŠธ const RealLicat = ({ licatSize }) => { useEffect(() => { console.log("์ปค์ ธ๋ผ, ๋ผ์ด์บฃ!"); }, [licatSize]); return <img src={licat} alt="๋ผ์ด์บฃ์ด๋ฏธ์ง€" style={licatStyle} />; }; return ( <> <h2>๐Ÿ“ ๋ผ์ด์บฃ์˜ ํ˜„์žฌ ํ‚ค๋Š” {licatSize}px</h2> <img src={building} alt="๋นŒ๋”ฉ" /> <button onClick={() => setLicatSize(licatSize * 2)}>๐Ÿช„</button> <RealLicat /> <MemoMessage who="๐ŸŸฆ" say={blueSay} toggle={toggleBlue} /> <MemoMessage who="๐ŸŸจ" say={yellowSay} toggle={toggleYellow} /> <img src={friends} alt="ํŒŒ์ด์ฌ ์นœ๊ตฌ๋“ค" /> </> ); }
๐Ÿช„ย ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, RealLicat์€ 2๋ฐฐ๋กœ ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๊ณ  <h2>์š”์†Œ์— ํ˜„์žฌ ์ƒํƒœ๊ฐ’์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๐ŸŸฆ์˜ ์ธ์‚ฌ ๋˜๋Š” ๐ŸŸจ์˜ ์ธ์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, Boolean ๊ฐ’์— ๋”ฐ๋ผ โ€œ์•ˆ๋…•~โ€ ๋˜๋Š” โ€œ๋ผ์ด์บฃ!โ€์˜ ๋ฌธ๊ตฌ๊ฐ€ ๋‚˜ํƒ€๋‚˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. React.memo์™€ useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ, ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ฝ˜์†”์ฐฝ์—์„œ ์–ด๋–ค ์ผ๋“ค์ด ๋ฒŒ์–ด์ง€๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
notion imagenotion image
๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ์„ ํ•œ๋ฒˆ์”ฉ ๋ˆŒ๋ €์„ ๋ฟ์ธ๋ฐ, ํ•ด๋‹น ๋ฒ„ํŠผ๊ณผ ๊ด€๋ จ์ด ์—†๋Š” ํ•จ์ˆ˜๋„ ํ•จ๊ป˜ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 
function Message({ who, say, toggle }) { console.log({ who, say }); return ( <> <div className="message">{say ? "๋ผ์ด์บฃ!" : "์•ˆ๋…•~"}</div> <button onClick={toggle}>{who}์˜ ์ธ์‚ฌ</button> </> ); } const MemoMessage = React.memo(Message);
์œ„ ์ฝ”๋“œ์˜ // โ€”โ€”- (1)์— ์œ„์น˜ํ•˜๋Š” ์ฝ”๋“œ
์œ„ ์ฝ”๋“œ๋Š” who , say , toggle ์„ props๋กœ ๋‚ด๋ ค ์ฃผ๋Š” Message ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ , React.memo๋กœ ๊ฐ์‹ธ์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ณผ๋กœ, props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ์—๋งŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์ด๋ฃจ์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
ย 
์‹ค์Šต2์—์„œ๋Š” yellowSay , blueSay , licatSize 3๊ฐœ์˜ state๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋จผ์ €, yellowSay์™€ blueSay state์—๋งŒ useCallback Hook์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณ€ํ™”๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
// ์ด์ „ ์ฝ”๋“œ const toggleYellow = () => setYellowSay(!yellowSay); const toggleBlue = () => setBlueSay(!blueSay); // useCallback์„ ์ถ”๊ฐ€ํ•œ ์ฝ”๋“œ const toggleYellow = useCallback(() => setYellowSay(!yellowSay), [yellowSay]); const toggleBlue = useCallback(() => setBlueSay(!blueSay), [blueSay]);
notion imagenotion image
๐Ÿช„ย ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ์ฝ˜์†”์ฐฝ์—๋Š” โ€œ์ปค์ ธ๋ผ, ๋ผ์ด์บฃ!โ€ ๋ฌธ๊ตฌ๋งŒ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๐ŸŸฆ์˜ ์ธ์‚ฌย ๋ฒ„ํŠผ๋„ ๋ˆŒ๋Ÿฌ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ licatSize๋Š” ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚ฌ์ง€๋งŒ, ๋‘๋ฒˆ์งธ ์ธ์ž์— ๋ณ€์ˆ˜๋ฅผ ์ง€์ •ํ•œ useCallback์€ ํ•ด๋‹น ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ ๊ฒƒ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
ย 
useCallback Hook ์ฑ•ํ„ฐ๋ฅผ ๋๋งˆ์น˜๋ฉฐ, ์„ฑ๋Šฅ ์ตœ์ ํ™”์—๋Š” ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ, ์œ ์ง€๋ณด์ˆ˜์˜ ์–ด๋ ค์›€, ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€ ๋“ฑ์˜ ๋‹จ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ ๊ณผ ์žฅ์ ์„ ๋น„๊ตํ•˜์—ฌ useCallback์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

7.4.1 ์ตœ์ข…์ฝ”๋“œ

import React, { useState, useEffect, useCallback } from "react"; import "./style.css"; import licat from "./licat.png"; import friends from "./friends.png"; import building from "./building.png"; function Message({ who, say, toggle }) { console.log({ who, say }); return ( <> <div className="message">{say ? "๋ผ์ด์บฃ!" : "์•ˆ๋…•~"}</div> <button onClick={toggle}>{who}์˜ ์ธ์‚ฌ</button> </> ); } Message = React.memo(Message); export default function App() { const [yellowSay, setYellowSay] = useState(false); const [blueSay, setBlueSay] = useState(true); const [licatSize, setLicatSize] = useState(50); const toggleYellow = useCallback(() => setYellowSay(!yellowSay), [yellowSay]); const toggleBlue = useCallback(() => setBlueSay(!blueSay), [blueSay]); const licatStyle = { width: `${licatSize}px`, height: `${licatSize}px`, }; const RealLicat = ({ licatSize }) => { useEffect(() => { console.log("์ปค์ ธ๋ผ, ๋ผ์ด์บฃ!"); }, [licatSize]); return <img src={licat} alt="๋ผ์ด์บฃ์ด๋ฏธ์ง€" style={licatStyle} />; }; return ( <> <h2>๐Ÿ“ ๋ผ์ด์บฃ์˜ ํ˜„์žฌ ํ‚ค๋Š” {licatSize}px</h2> <div className="background"> <img src={building} alt="๋นŒ๋”ฉ" /> <div className="bigger-licat"> <button onClick={() => setLicatSize(licatSize * 2)}>๐Ÿช„</button> <RealLicat /> </div> <div className="python-friends"> <div> <Message who="๐ŸŸฆ" say={blueSay} toggle={toggleBlue} /> <Message who="๐ŸŸจ" say={yellowSay} toggle={toggleYellow} /> </div> <img src={friends} alt="ํŒŒ์ด์ฌ ์นœ๊ตฌ๋“ค" /> </div> </div> </> ); }
App.js
.background { background-color: rgb(203, 228, 250); display: flex; flex-direction: row; } .bigger-licat, .python-friends { display: flex; flex-direction: column; align-self: flex-end; } .message { background-color: white; display: inline-block; padding: 5px; border-radius: 5px; margin: 10px 3px 10px 65px; }
style.css
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
โ—
[๋ชฉ์ฐจ]
  1. ์ •์˜(useMemo์™€ ์ฝ”๋“œ ๋น„๊ต) - ๋ฏผ์ œ๋‹˜
  1. ์‚ฌ์šฉ ์ด์œ (+์žฅ์ )/์‚ฌ์šฉํ•ด์•ผ ํ•  ๋•Œ (์˜ˆ์ œ : ๊ฐœ์„ ํ•˜๊ธฐ ์ „ ์ฝ”๋“œ , useCallback์œผ๋กœ ๊ฐœ์„ ํ•œ ์ฝ”๋“œ) - ํ˜œ์œค๋‹˜
  1. useCallback ์‚ฌ์šฉํ•ด๋ณด๊ธฐ - ์Šน๋ฏธ, ์ง€ํ•ด๋‹˜
    1. 3.1 useCallback ์‚ฌ์šฉ๋ฒ• (์™„์ „ ๊ธฐ๋ณธ ๋ฌธ๋ฒ•! ๋ฌธ๋ฒ•์‹!) 3.2 useCallback ์˜ˆ์ œ(+์˜์กด์„ฑ ๋ฐฐ์—ด์˜ state๊ฐ’์ด ๋ณ€ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋ฅผ ์˜ˆ์‹œ๋กœ ์ฃผ์˜์‚ฌํ•ญ ์ ์–ด์ฃผ๊ธฐ) -> input ์˜ˆ์ œ 3.3 useCallback ์˜ˆ์ œ2 -> ๋ผ์ด์บฃ ์ปค์ง€๊ธฐ 3.4 ๋งˆ๋ฌด๋ฆฌ(useCallback์„ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋˜๋Š” ์ƒํ™ฉ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํ•ด์ฃผ๊ธฐ)
์ž๋ฃŒ์กฐ์‚ฌ
ย 
์Šน๋ฏธ๋‹˜ : useCallback ์‚ฌ์šฉ ์ „ํ›„ + ์ฝœ์•„์›ƒ(์˜์กด์„ฑ๋ฐฐ์—ด ๊ด€๋ จ ์ฃผ์˜์‚ฌํ•ญ)
์ง€ํ•ด๋‹˜ : useMemo์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๋ถ€๋ถ„ ์ถ”๊ฐ€
ย 
ย