ํ์์ ๊ณต๋ถ๋ ํด๋จ์ง๋ง ํฐ ํ๋ก์ ํธ๋ฅผ ํ์ง์์ ๋ ๋๋ง ์ต์ ํ์ ํฌ๊ฒ ์ ๊ฒฝ์ฐ์ง ์์๋ค.
์ง๊ธ ํ๋ ๋ธ๋ก๊ทธ ํ๋ก์ ํธ๋ ๋ค๋ฅธ ๋ํ ํ๋ก์ ํธ์ ๋นํ๋ฉด ํฌ๊ฒ ๋ ๋๋ง์ ์ ์ํฅ์ ์ฃผ์ง ์์ง๋ง state๊ฐ ๋ณต์กํด์ง๊ณ Component์๋ ๋ง์์ง๋งํผ ์ต์ ํ๋ฅผ ํด์ฃผ๋ ๊ฒ์ ์์ผ๋ก์ ์ข์ ์ต๊ด์ด ๋ ๊ฒ ๊ฐ์ ์ต์ ํ์ ๋ํ์ฌ ๋ค์ ๋์ง๊ณ ๊ฐ๋ณด๊ณ ์ ํ๋ค.
Memoization์ด๋ ๊ธฐ์กด์ ์๋ ๊ฐ(ํจ์,๊ฐ์ฒด ๋ฑ)์ ์ฌ์ฉํ์ฌ ๋น์ฉ์ ์ค์ผ ์ ์๋ ์ต์ ํ๊ธฐ์ ์ด๋ค.
๊ฐ์ input์ด ๋ค์ด์์ ๋ ์๋กญ๊ฒ ๋ง๋๋ ๊ฒ์ด ์๋ ๊ธฐ์กด์ ์๋ ๊ฐ์ ์ฌ์ฉํ๋ค.
caching๊ณผ ๋น์ทํ์ง๋ง memoization์ ์ต์ ํ์ ์ด์ ์ ๋ง์ถ๊ณ ์๋ค.
useCallback, useMemo , React.memo์ memoization์ ๊ฐ๋ ๊ณผ ๋น์ทํ๋ค.
๊ธฐ์กด์ ์๋ ํจ์,๊ฐ,์ปดํฌ๋ํธ๋ค์ด ๋ฐ๋์ง์๋๋ค๋ฉด ์ด์ ์ ์๋ ๊ฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
ํ๋์ฉ ์ฐจ๋ก์ฐจ๋ก ์์๋ณด๋๋ก ํ์.
useCallback์ ๋ณด๊ธฐ์ ์ ๋ค์ ์์ ๋ฅผ ์ดํด๋ณด์.
function factory() {
return (a, b) => a + b;
}
const sum1 = factory();
const sum2 = factory();
sum1(1, 2); // => 3
sum2(1, 2); // => 3
sum1 === sum2; // => false
sum1 === sum1; // => true
factory๋ผ๋ ํจ์๊ฐ ๋ง๋ค์ด๋ด๋ sum1,sum2์ ๊ฐ์ ํจ์๋ก๋ถํฐ ๋ฐํ๋ ํจ์์ด์ง๋ง ๋น๊ต๋ฅผ ํด๋ดค์ ๋ ๋ค๋ฅธ ํจ์๋ก ํ๋จ๋๊ณ ์๋ค.
์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ฒด์ ๊ฐ๋ ์ ๋ค์ฌ๋ค๋ด์ผํ๋ค.
์ ์์ ๋ฅผ ์ดํดํ๊ธฐ์ํด ์์์ผํ ๊ฐ๋
์ ๋ค์๊ณผ ๊ฐ๋ค.
1. ํจ์๋ ์ผ๊ธ๊ฐ์ฒด์ด๋ค.์ฆ, ํจ์๋ ๊ฐ์ฒด์ด๋ค.
2. ๋ ๊ฐ์ฒด๋ฅผ ์์ฑํ์ ๋, key,value๊ฐ์ด ๊ฐ์๋ ๋ ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด์ด๋ค.
const obj1 = { x: 1, y: 2 };
const obj2 = { x: 1, y: 2 };
console.log(obj1 === obj2); //false
1๋ฒ ์ฌํญ์ ์ค๋ช
ํ์๋ฉด javascript์ ๊ฐ๋ค์ ๋๋ถ๋ถ ๊ฐ์ฒด๋ก ์ด๋ฃจ์ด์ ธ์๋ค.
ํจ์ ๋ํ ๊ฐ์ฒด๋ผ๊ณ ์๊ณ ์์ผ๋ฉด ๋๋ค.
2๋ฒ ์ฌํญ์ ์ ์์ ๋ฅผ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด ๋ ๊ฐ๋ key,value๊ฐ์ด ๊ฐ์๋ฐ๋ ๋น๊ต๋ฅผ ํด๋ดค์ ๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ผ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ด๋ ๋ด๋ถ์ ์ผ๋ก ์ด๋ ํ ์์ฑ๋ ๊ฐ์ฒด๋ ๋ค๋ฅธ ๊ฐ์ฒด์ ๋ค๋ฅธ ๊ณ ์ ํ ๊ฐ์ด๋ผ๋ ๊ฒ์ด๋ค.
์ถ๊ฐ ์ค๋ช : ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ํ๊ฐ๋ ๋๋ง๋ค ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค. obj1๊ณผ obj2์ ๋ด์ฉ์ ๊ฐ์ง๋ง ๋ค๋ฅธ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋ ๋ณ๊ฐ์ ๊ฐ์ฒด์ด๋ค. ์ฆ ,obj1๊ณผ obj2์ ์ฐธ์กฐ ๊ฐ์ ์ ํ ๋ค๋ฅธ ๊ฐ์ด๋ค.
๋ฐ๋ผ์ ์ฒ์์ ๋ณธ ์์ ๋ฅผ ๋ค์ ์ดํด๋ณด๋ฉด sum1()ํจ์์ sum2()ํจ์๊ฐ ๋ค๋ฅด๋ค๋ ๊ฒ์ ์ดํดํ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ค์์ผ๋ก React์ ์์ ๋ฅผ ์ดํด๋ณด์.
import React, { useState } from "react";
const App = () => {
const [value, setValue] = useState("");
const changeValue = (e) => setValue(e.target.value);
return (
<div>
<input value={value} onChange={changeValue} />
</div>
);
};
export default App;
์ ์์ ์์ input์ด onChange์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค changeValue ํจ์๊ฐ ์๋ก ์์ฑ๋๊ณ ์๋ค.
onChange๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์์ฑ๋๋ changeValue๋ ๊ฐ์ ํจ์์ผ๊น? ๋ค๋ฅธ ํจ์์ผ๊น?
๋ด๋ถ์ ์ผ๋ก ๋ค๋ฅธ ํจ์๊ฐ์ฒด์ด๋ค.
ํ์ง๋ง ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋๋ง๋ค ์์ฑ๋๋ ํจ์๋ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๋ฐํํ๋ ํจ์์ด๋ค.
๋๋ฌธ์ ์ฒ์ ํ๋ฒ ์์ฑํ ํจ์๋ฅผ ๊ณ์ ์ฌ์ฉํด๋ ๋๋ค๋ ์ด์ผ๊ธฐ์ด๋ค.
์ด๋ด ๋ useCallback์ ์ฌ์ฉํ๋ฉด ๋๋ ๊ฒ์ด๋ค.
useCallback
import React, { useState, useCallback } from "react";
const App = () => {
const [value, setValue] = useState("");
const changeValue = useCallback((e) => setValue(e.target.value), []);
return (
<div>
<input value={value} onChange={changeValue} />
</div>
);
};
export default App;
์์ ๊ฐ์ด useCallback์ ํด๋น ํจ์์ ์ฌ์ฉํด์ฃผ๋ฉด onChange ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋ ํ๋ฒ changeValue ํจ์๊ฐ ์์ฑ๋๊ณ ๊ทธ ๋ค๋ก changeValue๋ฅผ ์๋ก ์์ฑํ์ง ์๋๋ค.
์ฌ๊ธฐ์ ํท๊ฐ๋ฆฌ์ง ์์์ผํ๋์ ์ด ํจ์๊ฐ ์๋ก ์์ฑ๋์ง ์๋๋ค๋ ๊ฒ์ด ํจ์๊ฐ ์๋ํ์ง ์๋๋ค๋ ๊ฒ์ด ์๋๋ค. ๋จ์ง ๊ธฐ์กด์ ์ฒ์ ๋ง๋ค์๋ ํจ์๋ฅผ ๊ธฐ์ตํ์ฌ ๊ณ์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค.
useCallback์ ํํ
useCallback(callbackFuncition,[dependency])
useCallback์ useEffect์ ๋น์ทํ ํํ์ด๋ค.
์ฒซ๋ฒ์งธ ์ธ์์๋ ์คํํ๊ณ ์ ํ๋ ํจ์๋ฅผ ํ ๋นํ๊ณ ๋๋ฒ์งธ ์ธ์์ธ dependency ๋ฐฐ์ด์ ํ ๋นํ๋ value์ ๋ณํ๊ฐ ์ผ์ด๋ ๋๋ง๋ค callbackFunction์ ์์ฑํด์ค๋ค.
ํ์ง๋ง ์ฃผ์ํ ๊ฒ์ ๋ชจ๋ ํจ์์ useCallback์ wrappingํ๋ ๊ฒ์ ๊ณ ๋ คํด๋ด์ผํ ์ํฉ์ผ ์ ์๋ค.
๋๋ก๋ useCallback์ผ๋ก wrappingํ ํจ์๋ฅผ ์ ์ํ๋ ๊ฒ์ด ๋ ๋๋ง๋ ๋๋ง๋ค ๋ถ๋ฌ์ง๋ ๊ฒ์ด ๋น์ฉ์ด ๋ ํด ์ ์๋ค.
๋ฆฌ์กํธ ๊ณต์๋ฌธ์์์๋ ๋ ๋๋งํ ๋ ์ฌ์์ฑ๋๋ ๊ฐ์ ๋น์ฉ์ด ํด ๋ ์ฌ์ฉํ๋ผ๊ณ ๋์์๋ค.
๋ฐ๋ผ์ ์ปดํฌ๋ํธ ๊ตฌ์กฐ๊ฐ ๋ณต์กํ์ง์๊ณ element๋ค์ด ๋ณต์กํ์ง ์๋ค๋ฉด useCallback ์ฐจ๋ผ๋ฆฌ ์ฐ์ง ์๋ ๊ฒ์ด ๋์ ์ ์๋ค.
๋๋ฌธ์ useCallback์ ์ฌ์ฉํ ๋ ๋น์ฉ์ธก๋ฉด์ ๊ณ ๋ คํด๋ณด๊ณ ์ฌ์ฉํ๋๋ก ํ์.
useMemo๋ useCallback๊ณผ ๋น์ทํ๋ค.
useCallback์ Memoized function์ ๋ฐํํ์ง๋ง
useMemo๋ Memoized value๋ฅผ ๋ฐํํด์ค๋ค.
๋จผ์ ๋ค์ ์์ ๋ฅผ ์ดํด๋ณด์.
import React, { useState } from "react";
const expensiveCalculation = (num) => {
console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = expensiveCalculation(count);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
export default App;
๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค Todo๋ฅผ ์ถ๊ฐํด์ฃผ๋ UI์ ๋ฒํผ์ ๋๋ฅผ ๋๋ง๋ค ์ซ์๋ฅผ 1์ฉ ์ฆ๊ฐ์์ผ์ฃผ๋ UI๊ฐ ์๋ค.
์ด ๋ ์ซ์๋ฅผ ์ฆ๊ฐ์์ผ์ฃผ๋ UI์ ๋ฒํผ์ ๋๋ฅด๋ฉด 10์ต๋ฒ์ด๋ ๊ณ์ฐ์ ํ๋expensiveCalculation ํจ์๊ฐ ํธ์ถ๋๋ค.
ํ์ง๋ง ์ App ์ปดํฌ๋ํธ๋ todos๋ผ๋ state๊ฐ ๋ณ๊ฒฝ๋๋ ๋ฆฌ๋ ๋๋ง์ด ๋๊ธฐ ๋๋ฌธ์ Todo UI Button์ ํด๋ฆญํ์ฌ๋ expensiveCalculation ํจ์๊ฐ ํธ์ถ์ด ๋๋ค.
์ด๋ ์ฑ๋ฅ์ ์ ์ข์ ์ํฅ์ ๋ฏธ์น๋ ์์์ด๊ธฐ ๋๋ฌธ์ ์ต์ ํ๊ฐ ํ์ํ๋ค.
์ด ๋ ํ์ํ ํ
์ด useMemo์ด๋ค.
์ ์์ ์ useMemo๋ฅผ ์ ์ฉํด๋ณด์.
import React, { useState ,useMemo} from "react";
const expensiveCalculation = (num) => {
console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count), [count]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};
export default App;
์์ ๊ฐ์ด ์ ์ฉํด์ค๋ค๋ฉฐ todo UI ๋ฒํผ์ด ํด๋ฆญ๋์ด๋ expensiveCalculation์ด ํธ์ถ๋์ง ์๋๋ค.
useMemo์ ํํ
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useCallback๊ณผ ๋น์ทํ๊ฒ ์ฒซ๋ฒ์งธ ์ธ์์๋ ์ฝ๋ฐฑํจ์๋ฅผ ํ ๋นํด์ฃผ๊ณ ๋๋ฒ์งธ์ธ์์๋ dependency๋ฐฐ์ด์ ํ ๋นํด์ค๋ค.
dependency๊ฐ์ด ๋ฐ๋์ง ์์ผ๋ฉด computeExpensiveValue๋ ํธ์ถ๋์ง ์๋๋ค.
useMemo๋ useCallback๊ณผ ๋น์ทํ๋ ์ฐจ์ด์ ์ ๋ค์๊ณผ ๊ฐ๋ค.
useCallback๋ ์ฝ๋ฐฑํจ์์ธ ํจ์๋ฅผ memoizingํ๋ ๊ฒ์ด๊ณ
useMemo์ ์ฝ๋ฐฑํจ์์ ๋ฐํ๊ฐ์ ๊ธฐ์ตํ๋ ๊ฒ์ด๋ค.
๋๋ฌธ์ ์ด๋ฅผ ์ฌ์ฉํ ๋ ํท๊ฐ๋ฆฌ์ง ์๋๋ก ์ฃผ์๊น๊ฒ ์ดํด๋ณด๊ณ ์ฌ์ฉํ ํ์๊ฐ ์๋ค.
useMemo ๋ํ ๋น์ผ ์ฐ์ฐ์ด ์๋๋ผ๋ฉด ์ฌ์ฉํ ํ์๊ฐ ์๋ค๋ ๊ฒ์ ๊ธฐ์ตํด๋์.
React.memo๋ ์ ์ ํฌ์คํ
์ ํด๋๊ฒ์ด ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ตํ๊ฒ ์ค๋ช
ํ์๋ฉด
์ปดํฌ๋ํธ๋ฅผ memoizationํ๋ ๊ฒ์ด๋ค.
์ฆ, ์ปดํฌ๋ํธ์ ๋ณํ๊ฐ ์๋ค๋ฉด ๋ฆฌ๋ ๋๋ง์ด ๋์ง ์๋๋ก ํด์ค ๋ ์ฌ์ฉํ๋ค.
๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
๋ถ๋ชจ ์ปดํฌ๋ํธ์์ ์ ์ฒ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ์๋คํ์์ ๋ , ๋ถ๋ชจ์ state๊ฐ์ด ๋ฐ๋๋ฉด ์์ฒ๊ฐ์ ์ปดํฌ๋ํธ๊ฐ ๋ฆฌ๋ ๋๋ง๋ ๊ฒ์ด๋ค.
ํ์ง๋ง ๋ถ๋ชจ state์ ์ํฅ์ ๋ฐ์ง ์๋ ์ฆ, ๋ถ๋ชจ state๊ฐ ๋ฐ๋์ด๋ ์์ ์ปดํฌ๋ํธ๊ฐ ๋ณ๊ฒฝ๋์ง ์๋๋ค๋ฉด ์ด์ ์ปดํฌ๋ํธ๋ฅผ ๊ทธ๋๋ก ์ธ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ์ด React.memo์ด๋ฉฐ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
import React from "react"
export default fuction React.memo(ChildComponent(){
return <div>Child</div>
})
์ปดํฌ๋ํธ๋ฅผ ์์ฒ๋ผ React.memo๋ก ๊ฐ์ธ์ฃผ๋ฉด ๋๋ค.
React๋ฅผ ์ฌ์ฉํ ๋ Memoizingํ๋ ์ฃผ์ ๋ฐฉ๋ฒ๋ค์ ์ ๋ฆฌํด๋ณด์๋ค.
๋ถํ์ํ๊ฒ Memoizingํ๋ ๊ฒ๋ ๊ณ ๋ คํด๋ด์ผํ ์ฌํญ์ด์ง๋ง ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ํด ๋ ์ปดํฌ๋ํธ๊ฐ ๋ง์์ง๊ณ ํจ์ํธ์ถ๋์ด ๋ง์์ง๊ณ ๋น์ผ ์ฐ์ฐ๊ฐ์ด ๋ง์์ ธ ์ด๋ค์ด ๋ชจ๋ ํฉ์ณ์ง ๋ ๋น์ฉ์ด ๊ฝค ์ปค์ง๊ฒ ๋๋ค.
๊ทธ๋ฌ๋ฏ๋ก ํ๋ก์ ํธ๋ฅผ ๊ตฌ์ฑํ ๋ ์ด์ ์ ๊ณ ๋ คํ์ฌ Memozing์ ์ฌ๋ถ๋ฅผ ์ ํ๋จํด๋ณด์.