๐Ÿ“ช

7. 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๋‚˜ props๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ์ปดํฌ๋„ŒํŠธ๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ ์‚ฌ์šฉ์ž๋กœ๋ถ€ํ„ฐ ์ž…๋ ฅ๋ฐ›๋Š” 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๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ธด๋‹ค๋ฉด, ์–ด๋–ค ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„๊นŒ์š”?
ย 
๊ทธ๋ฆผ 7-1๊ทธ๋ฆผ 7-1
๊ทธ๋ฆผ 7-1
ย 
์ฒ˜์Œ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๋ฉด, useEffect๊ฐ€ ๋งˆ์šดํŠธ๋ฉ๋‹ˆ๋‹ค. ์ฝ˜์†”์ฐฝ์— ๋ณด์ด๋Š” ๋ฉ”์„ธ์ง€๋Š” useEffect๊ฐ€ ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ด์ œ ๋ผ์ด์บฃ์˜ ์™ธ์ถœ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
๊ทธ๋ฆผ 7-2๊ทธ๋ฆผ 7-2
๊ทธ๋ฆผ 7-2
ย 
๋ถ„๋ช… ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ๋งŒ ํด๋ฆญํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— 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 ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 
ย 
๊ทธ๋ฆผ 7-3๊ทธ๋ฆผ 7-3
๊ทธ๋ฆผ 7-3
ย 
์‹คํ–‰ํ™”๋ฉด์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด 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]); // --- โ‘ก ๊ฐ’์„ ๋„ฃ์—ˆ์„ ๋•Œ
ย 
๊ทธ๋ฆผ 7-4๊ทธ๋ฆผ 7-4
๊ทธ๋ฆผ 7-4
๊ทธ๋ฆผ 7-5๊ทธ๋ฆผ 7-5
๊ทธ๋ฆผ 7-5
ย 
์ฝ˜์†” ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•ด๋ณด๋ฉด, ๋ผ์ด์บฃ ์ด๋™! ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ๋งˆ๋‹ค licatLocation ํ•จ์ˆ˜ ํ˜ธ์ถœ! ๋ฉ”์„ธ์ง€๊ฐ€ ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ state ๊ฐ’์— ๋”ฐ๋ผ ์™ผ์ชฝ ํ™”๋ฉด์— ์ถœ๋ ฅ๋˜๋Š” state ๊ฐ’๊ณผ licatLocation ํ•จ์ˆ˜๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” state ๊ฐ’์ด ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

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

๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ Œ๋”๋ง ๋˜๋ฉด ์ž์‹ ์ปดํฌ๋„ŒํŠธ๋„ ๋ Œ๋”๋ง ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ props๊ฐ€ ๊ฐ™์€ ์ฃผ์†Œ์ผ ๊ฒฝ์šฐ, ์ฃผ์†Œ๋ฅผ ๋น„๊ตํ•œ ํ›„ ๋ฆฌ๋ Œ๋”๋งํ•˜๋Š” React.memo๋กœ ๊ฐ์‹ธ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ์‹ค์Šต์—์„œ๋Š” React.memo์™€ useCallback์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฐ ๋ถˆํ•„์š”ํ•œ ๋ฆฌ๋ Œ๋”๋ง์„ ์ค„์ด๋Š” ๊ฒƒ์— ๋ชฉ์ ์„ ๋‘์—ˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ์œ„ํ•ด ์Šคํƒ€์ผ๋ง ์ฝ”๋“œ๋Š” ์ œ์™ธํ•˜๊ณ  ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
* 7.4.3 ์ตœ์ข… ์ฝ”๋“œ์— ์Šคํƒ€์ผ๋ง ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. * ์ด๋ฏธ์ง€ ์ถœ์ฒ˜ - WeNiv
ย 
๊ทธ๋ฆผ 7-6 : ์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ๊ทธ๋ฆผ 7-6 : ์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ
๊ทธ๋ฆผ 7-6 : ์‹ค์Šต2 ๊ฒฐ๊ณผ๋ฌผ
ย 
2๋ฐฐ ์„ฑ์žฅ!๐Ÿช„ย ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, RealLicat์€ 2๋ฐฐ๋กœ ํฌ๊ธฐ๊ฐ€ ์ปค์ง€๊ณ  <h2> ์š”์†Œ์— ํ˜„์žฌ ์ƒํƒœ ๊ฐ’์ธ licatSize๊ฐ€ ํ™”๋ฉด์— ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ๐ŸŸฆ์˜ ์ธ์‚ฌ ๋˜๋Š”ย ๐ŸŸจ์˜ ์ธ์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด,ย Boolean ๊ฐ’์ด true์ผ ๋•Œ โ€œ์•ˆ๋…•!โ€ ๋ฌธ๊ตฌ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. React.memo์™€ useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ, ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์ฝ˜์†” ์ฐฝ์—์„œ ์–ด๋–ค ์ผ๋“ค์ด ๋ฒŒ์–ด์ง€๋Š”์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 

7.4.1 React.memo์™€ useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ

ย 
import React, { useState, useEffect } 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 ( <> {say ? <div className="message">์•ˆ๋…•!</div> : null} <button onClick={toggle}>{who}์˜ ์ธ์‚ฌ</button> </> ); } // --- โ‘  export default function App() { const [blue, setBlue] = useState(false); const [yellow, setYellow] = useState(false); const [licatSize, setLicatSize] = useState(50); const toggleBlue = () => setBlue(!blue); // --- โ‘ก const toggleYellow = () => setYellow(!yellow); const doubleLicat = () => setLicatSize(licatSize * 2); const RealLicat = () => { return ( <img src={licat} alt="๋ผ์ด์บฃ ์ด๋ฏธ์ง€" style={{ width: `${licatSize}px`, height: `${licatSize}px` }} /> ); }; useEffect(() => { console.log("๋ผ์ด์บฃ์ด 2๋ฐฐ๋กœ ์ปค์กŒ๋‹ค!"); }, [licatSize]); return ( <> <h2>๐Ÿ“ ํ˜„์žฌ, ๋ผ์ด์บฃ์˜ ํ‚ค๋Š” {licatSize}px</h2> <button onClick={doubleLicat}>2๋ฐฐ ์„ฑ์žฅ!๐Ÿช„</button> <div className="background"> <img src={building} alt="๋นŒ๋”ฉ" /> <RealLicat /> <div className="python-friends"> <div className="message-wrapper"> <Message who="๐ŸŸฆ" say={blue} toggle={toggleBlue} /> <Message who="๐ŸŸจ" say={yellow} toggle={toggleYellow} /> </div> <img className="friends" src={friends} alt="ํŒŒ์ด์ฌ ์นœ๊ตฌ๋“ค ์ด๋ฏธ์ง€" /> </div> </div> </> ); }
ย 
๊ทธ๋ฆผ 7-7๊ทธ๋ฆผ 7-7
๊ทธ๋ฆผ 7-7
ย 
๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ์„ ํ•œ ๋ฒˆ์”ฉ ๋ˆŒ๋ €์„ ๋•Œ, ํ•ด๋‹น ๋ฒ„ํŠผ๊ณผ ๊ด€๋ จ์ด ์—†๋Š” ํ•จ์ˆ˜๋„ ํ•จ๊ป˜ ๋ฆฌ๋ Œ๋”๋ง์ด ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ย 

7.4.2 React.memo์™€ useCallback์„ ์‚ฌ์šฉํ•  ๋•Œ

ย 
function Message({ who, say, toggle }) { console.log({ who, say }); return ( <> {say ? <div className="message">์•ˆ๋…•!</div> : null} <button onClick={toggle}>{who}์˜ ์ธ์‚ฌ</button> </> ); } const MemorizedMessage = React.memo(Message); // --- โ‘  ... <div className="message-wrapper"> <MemorizedMessage who="๐ŸŸฆ" say={blue} toggle={toggleBlue} /> <MemorizedMessage who="๐ŸŸจ" say={yellow} toggle={toggleYellow} /> </div>
ย 
์œ„ ์ฝ”๋“œ๋Š” who, say, toggle ์„ props๋กœ ๋‚ด๋ ค์ฃผ๋Š” Message ์ปดํฌ๋„ŒํŠธ์— React.memo๋กœ ๊ฐ์‹ธ์ฃผ๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ๋กœ, props๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ์—๋งŒ ํ•จ์ˆ˜ ํ˜ธ์ถœ์ด ์ด๋ฃจ์–ด์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
ย 
์‹ค์Šต2์—์„œ๋Š” yellow, blue, licatSize 3๊ฐœ์˜ state๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค. ๋จผ์ €, blue์˜ ํ•จ์ˆ˜์—๋งŒ useCallback์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณ€ํ™”๋ฅผ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
import React, { useState, useEffect, useCallback } from "react"; ... const toggleBlue = useCallback(() => setBlue(!blue), [blue]); // --- โ‘ก const toggleYellow = () => setYellow(!yellow);
ย 
๊ทธ๋ฆผ 7-8๊ทธ๋ฆผ 7-8
๊ทธ๋ฆผ 7-8
ย 
2๋ฐฐ ์„ฑ์žฅ!๐Ÿช„ย ๋ฒ„ํŠผ๊ณผ ๐ŸŸฆ์˜ ์ธ์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉดย useCallback์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ํ•จ์ˆ˜๋„ ํ•จ๊ป˜ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ๋ฐ˜๋ฉด, ๐ŸŸจ์˜ ์ธ์‚ฌ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด useCallback์„ ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜๋Š” ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ย 
๐Ÿ’ก
useCallback์€ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, React.memo๋กœ ๊ฐ์‹ธ์ง€ ์•Š์•˜์„ ๋•Œ
๊ทธ๋ฆผ 7-9๊ทธ๋ฆผ 7-9
๊ทธ๋ฆผ 7-9
ย 
๋งˆ์ง€๋ง‰์œผ๋กœ yellow์™€ licatSize ์˜ ํ•จ์ˆ˜์—๋„ useCallback์„ ์‚ฌ์šฉํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
ย 
const toggleBlue = useCallback(() => setBlue(!blue), [blue]); const toggleYellow = useCallback(() => setYellow(!yellow), [yellow]); const doubleLicat = useCallback(() => setLicatSize(licatSize * 2), [licatSize]);
ย 
๊ทธ๋ฆผ 7-10๊ทธ๋ฆผ 7-10
๊ทธ๋ฆผ 7-10
ย 
๊ฐ๊ฐ์˜ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ, useCallback์˜ ์˜์กด์„ฑ ๋ฐฐ์—ด์— ๋„ฃ์€ ํ•ด๋‹น state๊ฐ€ ๋ณ€ํ–ˆ์„ ๋•Œ๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ˜์†” ์ฐฝ์—์„œ ๋ณด์ด์ง€๋Š” ์•Š์ง€๋งŒ, setLicatSize ํ•จ์ˆ˜์— useCallback์„ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ๊ด€๋ จ ์—†๋Š” ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ๋•Œ ์ด๋ฏธ์ง€๊ฐ€ ํ•จ๊ป˜ ๋ฆฌ๋ Œ๋”๋ง ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
ย 
useCallback ์ฑ•ํ„ฐ๋ฅผ ๋๋งˆ์น˜๋ฉฐ, ์„ฑ๋Šฅ ์ตœ์ ํ™”์—๋Š” ์ฝ”๋“œ์˜ ๋ณต์žก์„ฑ, ์œ ์ง€๋ณด์ˆ˜์˜ ์–ด๋ ค์›€, ๋ฉ”๋ชจ๋ฆฌ ์ฆ๊ฐ€ ๋“ฑ์˜ ๋‹จ์ ์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์žฅ๋‹จ์ ์„ ๋น„๊ตํ•˜์—ฌ useCallback์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ย 

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

ย 
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 ( <> {say ? <div className="message">์•ˆ๋…•!</div> : null} <button onClick={toggle}>{who}์˜ ์ธ์‚ฌ</button> </> ); } const MemorizedMessage = React.memo(Message); export default function App() { const [blue, setBlue] = useState(false); const [yellow, setYellow] = useState(false); const [licatSize, setLicatSize] = useState(50); const toggleBlue = useCallback(() => setBlue(!blue), [blue]); const toggleYellow = useCallback(() => setYellow(!yellow), [yellow]); const doubleLicat = useCallback( () => setLicatSize(licatSize * 2), [licatSize] ); const RealLicat = () => { return ( <img src={licat} alt="๋ผ์ด์บฃ ์ด๋ฏธ์ง€" style={{ width: `${licatSize}px`, height: `${licatSize}px` }} /> ); }; useEffect(() => { console.log("๋ผ์ด์บฃ์ด 2๋ฐฐ๋กœ ์ปค์กŒ๋‹ค!"); }, [licatSize]); return ( <> <h2>๐Ÿ“ ํ˜„์žฌ, ๋ผ์ด์บฃ์˜ ํ‚ค๋Š” {licatSize}px</h2> <button onClick={doubleLicat}>2๋ฐฐ ์„ฑ์žฅ!๐Ÿช„</button> <div className="background"> <img src={building} alt="๋นŒ๋”ฉ" /> <RealLicat /> <div className="python-friends"> <div className="message-wrapper"> <MemorizedMessage who="๐ŸŸฆ" say={blue} toggle={toggleBlue} /> <MemorizedMessage who="๐ŸŸจ" say={yellow} toggle={toggleYellow} /> </div> <img className="friends" src={friends} alt="ํŒŒ์ด์ฌ ์นœ๊ตฌ๋“ค ์ด๋ฏธ์ง€" /> </div> </div> </> ); }
App.js
h2, .python-friends, .message { display: inline-block; } h2 { margin-right: 10px; } .background { background-color : rgb(203, 228, 250); padding: 5px; } .friends { width: 280px; } .message { background-color: white; padding: 5px; border-radius: 5px; margin: 0 3px 0 10px; } .message-wrapper { text-align: center; }
style.css
ย