import React, { useState } from "react";
import "./styles.css";
import { add } from "./add";
export default function App() {
const [name, setName] = useState("");
const [val1, setVal1] = useState(0);
const [val2, setVal2] = useState(0);
const answer = add(val1, val2);
return (
<div>
<input
className="name-input"
placeholder="이름을 입력해주세요"
value={name}
type="text"
onChange={(e) => setName(e.target.value)}
/>
<input
className="value-input"
placeholder="숫자를 입력해주세요"
value={val1}
type="number"
onChange={(e) => setVal1(Number(e.target.value))}
/>
<input
className="value-input"
placeholder="숫자를 입력해주세요"
value={val2}
type="number"
onChange={(e) => setVal2(Number(e.target.value))}
/>
<div>{answer}</div>
</div>
);
}
export const add = (num1, num2) => {
console.log("숫자가 들어옵니다.");
return Number(num1) + Number(num2);
};
최적화 전 실행 화면
실제로 연산 로직에 영향을 주는 값은 val1
과 val2
값인데,
보다시피 그 두 값이 아닌 name
값을 수정해도 add
함수가 계속 같은 결과값을 리턴함에도 불구하고 불필요하게 계속 호출되고 있는 상태이다.
useMemo
를 사용해서 add
함수의 호출을 최소화할 수 있다.
즉 이름을 입력할 때는 add
함수가 호출되지 않아야 최적화가 된 컴포넌트인 것.
import React, { useState, useMemo } from "react";
import "./styles.css";
import { add } from "./add";
export default function App() {
const [name, setName] = useState("");
const [val1, setVal1] = useState(0);
const [val2, setVal2] = useState(0);
// const answer = add(val1, val2);
const answer = useMemo(() => add(val1, val2), [val1, val2]);
// 이 줄 아래 코드는 최적화 전과 동일
기존의 answer
변수를 useMemo
를 사용해서 val1
와 val2
의 값이 변할때만 새로이 add
함수를 실행하고 그렇지 않을 경우에는 memoization 해 둔 answer
값을 재사용하도록 해주었다.
최적화 후 실행 화면
최적화를 하고 나니, 이제는 더이상 이름 값이 변경하더라도 add
함수가 실행되지 않는 것을 확인할 수 있다!
import { useState } from "react";
import "./styles.css";
import List from "./List";
export default function App() {
const [input, setInput] = useState(1);
const [light, setLight] = useState(true);
const theme = {
backgroundColor: light ? "White" : "grey",
color: light ? "grey" : "white"
};
const getItems = () => {
return [input + 10, input + 100];
};
const handleChange = (event) => {
if (Number(event.target.value)) {
setInput(Number(event.target.value));
}
};
return (
<>
<div style={theme} className="wall-paper">
<input
type="number"
className="input"
value={input}
onChange={handleChange}
/>
<button
className={(light ? "light" : "dark") + " button"}
onClick={() => setLight((prevLight) => !prevLight)}
>
{light ? "dark mode" : "light mode"}
</button>
<List getItems={getItems} />
</div>
</>
);
}
import { useState, useEffect } from "react";
function List({ getItems }) {
/* Initial state of the items */
const [items, setItems] = useState([]);
/* This hook sets the value of items if
getItems object changes */
useEffect(() => {
console.log("아이템을 가져옵니다.");
setItems(getItems());
}, [getItems]);
/* Maps the items to a list */
return (
<div>
{items.map((item) => (
<div key={item}>{item}</div>
))}
</div>
);
}
export default List;
최적화 전 실행 화면
보다시피 최적화 전에는 숫자 값이 아닌 다크모드 & 라이트모드
변경 테마 버튼을 클릭해도 getItem
함수가 불필요하게 실행되어 콘솔창에 "아이템을 가져옵니다."가 찍히는 것을 확인할 수 있다.
이 동작의 이유는 버튼을 누를 때도 앱이 리렌더링 되므로, App
내부의 getItems()
함수가 다시 만들어진다. 새로이 만들어진 함수는 이전의 함수와 참조 비교 시 다른 함수이기 때문에 List
구성 요소 내에서 useEffect
Hook은 setItems
를 호출하고 종속성이 변경됨에 따라 “아이템을 가져옵니다.”를 출력하는 것.
import { useCallback, useState } from "react";
import "./styles.css";
import List from "./List";
export default function App() {
const [input, setInput] = useState(1);
const [light, setLight] = useState(true);
const theme = {
backgroundColor: light ? "White" : "grey",
color: light ? "grey" : "white"
};
const getItems = useCallback(() => {
return [input + 10, input + 100];
}, [input]);
// 아래 코드는 모두 동일
최적화 후 실행 화면
useCallback
을 사용해서 getItems
함수를 input
의 값이 바뀔때만 실행하도록 하면 테마 값이 바뀌어도 불필요하게 getItems
함수가 호출되지 않는 것을 확인할 수 있다.