-
[React.js] useMemo개발 2021. 7. 14. 16:15
회사에서 useCallback을 사용해 성능 최적화를 해야할 일이 생겼고, useCallback이 useMemo를 기반으로 만들어졌다는 부분을 보고 나서 useMemo와 함께 리서치하기로 했다.
useMemo
는 특정 결과값을 재사용할 때 사용하고,useCallback
은 특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용한다고 한다. 메모이제이션(계산된 값을 자료구조에 저장하고 이후 같은 계산을 반복하지 않고 자료구조에서 꺼내 재사용하는 것)에 대해 알고 있어야 한다.
아래의 예제 코드는 https://www.youtube.com/watch?v=THL1OPn72vo 에서 사용한 예제이다.
useMemo(어떻게 연산할지 정의하는 함수, deps 배열)
import React, { useState, useMemo } from "react"; export default function App() { const [number, setNumber] = useState(0); const [dark, setDark] = useState(false); const doubleNumber = slowFunction(number); const themeStyles = { backgroundColor: dark ? "black" : "white", color: dark ? "white" : "black", }; return ( <> <input type="number" value={number} onChange={(e) => setNumber(parseInt(e.target.value))} /> <button onClick={() => setDark((prevDark) => !prevDark)}> Change Theme </button> </> ); } function slowFunction(num) { console.log("Calling Slow Function"); for (let i = 0; i <= 1000000000; i++) {} return num * 2; }
slowFunction에서 동작하는 for문으로 인해 재렌더링 되는 속도가 느리다. doubleNumber에서 slowFunction을 호출하는 부분을 useMemo로 감싸본다.
const doubleNumber = useMemo(() => { slowFunction(number); }, [number]);
[number]를 감지하여, number가 변경되지 않으면 다시 실행할 필요가 없다.
useMemo는 이전 값을 일부 메모리 변수에 저장하므로, 사용할 때마다 강제로 메모리를 늘려야한다. 해당 이유로 불필요하게 모든 곳에서 useMemo를 사용하는 것은 옳지 않다.
객체와 배열의 경우 참조를 비교하는데,
const themeStyles = { backgroundColor: dark ? "black" : "white", color: dark ? "white" : "black", }; const themeStyles2 = { backgroundColor: dark ? "black" : "white", color: dark ? "white" : "black", };
해당 themeStyles와 themeStyles2는 동일하다고 생각될 수 있지만 자바스크립트에서 그들은 동일한 값을 가졌을 뿐 두개의 다른 객체라고 판단한다.
이 이유로, 상단 코드에서 추가로 아래의 useEffect 구문을 추가하여 콘솔을 확인하면, number가 바뀌는 순간에도 테마 변경이 실행된다는 것을 알 수 있다.
useEffect(() => { console.log('Theme Changed'); }, [themeStyles])
개선하기 위해 themeStyles 를 useMemo로 감싸본다. dark가 변하는 것을 감지하여, 값이 변했을 때만 themeStyles 값을 바꾸고 재렌더링한다.
const themeStyles = useMemo(() => { return { backgroundColor: dark ? "black" : "white", color: dark ? "white" : "black" } }, [dark]);
마지막으로 전체코드!
import React, { useState, useMemo, useEffect } from "react"; export default function App() { const [number, setNumber] = useState(0); const [dark, setDark] = useState(false); const doubleNumber = useMemo(() => { slowFunction(number); }, [number]); const themeStyles = useMemo(() => { return { backgroundColor: dark ? "black" : "white", color: dark ? "white" : "black" } }, [dark]); useEffect(() => { console.log('Theme Changed'); }, [themeStyles]) return ( <> <input type="number" value={number} onChange={(e) => setNumber(parseInt(e.target.value))} /> <button onClick={() => setDark((prevDark) => !prevDark)}> Change Theme </button> </> ); } function slowFunction(num) { console.log("Calling Slow Function"); for (let i = 0; i <= 1000000000; i++) {} return num * 2; }
단순히 성능 최적화를 위해 사용된다고 알고 있던 헷갈리는 useMemo를 10분의 강의와, 블로깅으로 정리하며 이해할 수 있었다. 다음 글은 useCallback에 대해 진행할 예정이다.
'개발' 카테고리의 다른 글
Next.js 공부 (0) 2021.07.09