-
1-9 React Hooks - useMemoReact 숙련주차 2023. 5. 3. 18:51
렌더링 최적화 방법들
React.memo: 컴포넌트 캐싱
useCallback: 함수 캐싱
useMemo: value(함수return값) 캐싱
useMemo 사용방법// as-is const value = 반환할_함수(); // to-be const value = useMemo(()=> { return 반환할_함수() }, [dependencyArray]);
dependency Array의 값이 변경 될 때만 `반환할_함수()`가 호출된다.
그 외의 경우에는 memoization 해놨던 값을 가져오기만 한다.
App컴포넌트에 다음과같은 형식을 만든다.
네비게이션바
<HeavyComponent/>
푸터영역import React from 'react' import HeavyComponent from './components/HeavyComponent' // heavy work 만들어보기 function App() { return ( <> <nav style={{ backgroundColor: 'yellow', marginBottom: '30px', }}>네비게이션 바</nav> <HeavyComponent /> <footer style={{ backgroundColor: 'green', marginBottom: '30px', }}>푸터 영역이예요.</footer> </> ) } export default App
HeavyComponent파일에는 heavyWork를 만들어 0부터 1000000000전까지 돌게 하고,
100을 도출하게한다.
버튼에는 클릭하면 0부터 1씩늘어나도록한다.import React, {useState} from 'react' function HeavyComponent() { const [count, setCount] = useState(0); const heavyWork = () => { for(let i=0; i<1000000000; i++){} return 100; } const value = heavyWork(); return ( <> <p>나는 엄청 무거운 컴포넌트야!</p> <button onClick={()=>{ setCount(count+1) }} > 누르면 아래 카운트가 올라가요! </button> <br /> {count} </> ) } export default HeavyComponent
카운트 버튼을 누르면 heavyWork함수에 의해 리렌더링시간이 약간 딜레이되는것을 볼 수 있다.이럴때 useMemo를 이용해 heavyWork에서 return한값을 저장해 최적화한다.
(일단 HeavyComponent파일에서 useMemo를 import해온다)
그리고 value함수를 useMemo(()=>heavyWork(), [])로 감싸준다.
console.log(`value는 ${value}입니다.`) 해서 return한 value값도 같이 확인해보자.import React, {useState, useMemo} from 'react' function HeavyComponent() { const [count, setCount] = useState(0); const heavyWork = () => { for(let i=0; i<1000000000; i++){} return 100; } const value = useMemo(()=>heavyWork(), []) console.log(`value는 ${value}입니다.`) return ( <> <p>나는 엄청 무거운 컴포넌트야!</p> <button onClick={()=>{ setCount(count+1) }} > 누르면 아래 카운트가 올라가요! </button> <br /> {count} </> ) } export default HeavyComponent
이렇게하면 100으로 return한 ${value}값이 잘 들어온걸 확인할 수 있고,
카운트 버튼을 눌렀을때 리렌더링이 훨씬 빨리 되는것을 볼 수 있다.
dependency array를 활용하는 예시도 해보자.
useEffect를 이용해 [me]가 바뀔때마다 console.log("생존여부가 바뀔 때만 호출해주세요!") 하게 했다.
그래서 isAlive가 생존인지 사망인지에 따라 useEffect도 같이 console에 호출되었다.
그런데 아래에 있던 uslessCount가 리렌더링될때도 useEffect가 같이 console에 호출되었다.import React, { useEffect, useState } from "react"; function ObjectComponent() { const [isAlive, setIsAlive] = useState(true); const [uselessCount, setUselessCount] = useState(0); const me = { name: "Ted Chang", age: 21, isAlive: isAlive ? "생존" : "사망", }; useEffect(() => { console.log("생존여부가 바뀔 때만 호출해주세요!"); }, [me]); return ( <> <div> 내 이름은 {me.name}이구, 나이는 {me.age}야! </div> <br /> <div> <button onClick={() => { setIsAlive(!isAlive); }} > 누르면 살았다가 죽었다가 해요 </button> <br /> 생존여부 : {me.isAlive} </div> <hr /> 필요없는 숫자 영역이에요! <br /> {uselessCount} <br /> <button onClick={() => { setUselessCount(uselessCount + 1); }} > 누르면 숫자가 올라가요 </button> </> ); } export default ObjectComponent;
이유는 불변성 때문. 그래서 uselessCount부분의 state가 바뀌게 되면 리렌더링되면서 ObjectComponent 함수가 새로 호출된다.
그렇게 되면서 me객체도 다시 할당한다(이 때, me객체에 다른 메모리 주소값을 할당).
결국 useEffect입장에서는 me가 달라졌다고 인식하여 [me]에 의해 console.log를 호출하게된것이다.
그러므로 me객체의 값이 바뀌지 않았다는것을 알릴 수 있는 장치를 해서 useEffect의 호출을 막을 수 있다.const me = useMemo(()=>{ return { name: "Ted Chang", age: 21, isAlive: isAlive ? "생존" : "사망", } }, [isArray])
이렇게 useMemo함수로 객체를 감싸주면, 아래 uselessCount버튼을 눌러도 useEffect의 호출이 뜨지 않게된다.
다만 dependency array에 isArray를 넣어서 isArray의 상태가 바뀔때(토글버튼이 선택됐을때)만 useMemo가 발동되도록 한다.
주의사항
useMemo를 남발하게 되면 별도의 메모리 확보를 너무나 많이 하게 되기 때문에 오히려 성능이 악화될 수 있다고한다. (필요할 때만 쓰기!)
'React 숙련주차' 카테고리의 다른 글
1-11 DOM과 Virtual DOM (0) 2023.05.03 1-10 Lifecycle (0) 2023.05.03 1-8 React Hooks - useCallback (0) 2023.05.02 1-7 React Hooks - React.memo (1) 2023.05.02 1-6 React Hooks - useContext (0) 2023.04.30