반응형
참고
- https://legacy.reactjs.org/docs/hooks-reference.html#lazy-initial-state
- React.memo, useMemo, useCallback으로 최적화하기
이전 글에서 상태 변경에 의해 컴포넌트가 매번 렌더링 될 때 메모이제이션을 이용해 렌더링을 최적화하였다.
비슷한 최적화로 useState의 게으른 초기화(Lazy Initialization)를 사용할 수 있다.
useState의 초기화에서 함수를 사용하고 있는 경우를 살펴보자.
만약 value0이 getInitValue 함수로 값을 초기화한다고 가정하자.
const getInitValue = () => {
console.log("getInitValue");
return "";
}
const MemoTest = () => {
const [value0, setValue0] = useState(getInitValue());
그럼 컴포넌트가 다시 렌더링 될 때 마다 아래와 같이 getInitValue 로그가 출력되는 것을 알 수 있다.
렌더링에 의해 함수 컴포넌트( = useState 값)의 함수가 같이 실행되기 때문이다.
게으른 초기화는 단지 함수를 실행해 값을 반환하도록 수정만 하면 된다.
const [value0, setValue0] = useState(() => getInitValue());
// or const [value0, setValue0] = useState(() => { return getInitValue(); });
이제 getInitValue가 실행되지 않는다.
만약 getInitValue가 비용이 꽤 큰 작업이라면, 게으른 초기화를 사용하는 것이 좋다.
전체 코드는 다음과 같다.
import React, { useCallback, useMemo, useState } from "react";
const MySpan = ({ input }) => {
console.log("MySpan is Rendered...");
return <span>input 0 : {input}</span>;
};
const MySpanMemo = React.memo(MySpan);
const getInitValue = () => {
console.log("getInitValue");
return "";
}
const MemoTest = () => {
const [value0, setValue0] = useState(() => { return getInitValue(); });
const [value1, setValue1] = useState("");
const [value2, setValue2] = useState("");
const [number, setNumber] = useState(0);
const MySpanUseMemo = useMemo(() => <MySpan input={value0} />, [value0]);
const handleChange0 = (e) => {
console.log("change 0");
let input = e.target.value;
setValue0(input);
};
const handleChange1 = (e) => {
console.log("change 1");
let input = e.target.value;
setValue1(input);
};
const handleChange2 = (e) => {
console.log("change 2");
let input = e.target.value;
setValue2(input);
};
const upperCase = (input) => {
console.log("upper case", input);
return input.toUpperCase();
};
const lowerCase = (input) => {
console.log("lower case", input);
return input.toLowerCase();
};
const upperInput = useMemo(() => upperCase(value1), [value1]);
const lowerInput = lowerCase(value2);
const plusNumber = useCallback(() => {
console.log("plus number", number);
setNumber((prev) => prev + 1);
}, []);
return (
<div
style={{
margin: 5,
display: "flex",
flexDirection: "column",
width: 200,
}}
>
<input
type="text"
value={value0}
onChange={handleChange0}
placeholder="value 0"
/>
<input
type="text"
value={value1}
onChange={handleChange1}
placeholder="value 1"
/>
<input
type="text"
value={value2}
onChange={handleChange2}
placeholder="value 2"
/>
<MySpanMemo input={value0} />
{MySpanUseMemo}
<span>input 1 : {upperInput}</span>
<span>input 2 : {lowerInput}</span>
<button onClick={plusNumber}>+</button>
<span>number : {number}</span>
</div>
);
};
export default MemoTest;
반응형
댓글