Hook - useMemo, React.memo, useCallback
- 연산 최적화 할 때 사용
- Memoization : 이미 계산 해 본 연산 결과를 기억 해 두었다가 동일한 계산을 시키면, 다시 연산하지 않고 기억(캐싱) 해 두었던 데이터를 반환 시키게 하는 방법
🔽 useMemo
일반 함수로 작업시
//App=()=>{}안에 들어있으며, useEffect(()=>{},[])사용 중
const getDiaryAnalysis = () => {
const goodCount = data.filter((item)=>item.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return {goodCount, badCount, goodRatio}
}
const {goodCount, badCount, goodRatio} = getDiaryAnalysis()
//...결과값 사용 예시 생략
- 첫 로드시 2번 실행됨
1. App컴포넌트가 처음 Mount될 때
2. useEffect에서 사용한 getData()가 실행되면서 데이터를 가져온 후 App컴포넌트가 리렌더 될 때 - 다른 state를 수정 시에도 App컴포넌트가 리렌더되어 한번 더 작동하기에 불필요한 작업을 다시 하는건 비효율적임
useMemo hook 사용
useMemo(()=>{},[])
사용하여 필요 할 때에만 사용 가능
//App=()=>{}안에 들어있으며, useEffect(()=>{},[])사용 중
const getDiaryAnalysis = useMemo(() => {
const goodCount = data.filter((item)=>item.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100;
return {goodCount, badCount, goodRatio}
}, [data.length])
const {goodCount, badCount, goodRatio} = getDiaryAnalysis
//...결과값 사용 예시 생략
- getDiaryAnalysis는 더이상 함수호출이 아닌 useMemo내의 콜백함수의 return값을 바로 가진다.
- [ data.length ]가 바뀔 때에만 useMemo를 재실행한다.
🔽 React.memo
- 고차컴포넌트(HOC, Higher Order Component)
=> 컴포넌트를 가져와 새 컴포넌트를 반환하는 함수 - 컴포넌트 재 사용 : 부모컴포넌트가 재렌더 될 때 재렌더가 필요하지 않은 자식컴포넌트도 재렌더 되는걸 방지
=> 부모컴포넌트의 스테이트가 바뀔 때 재렌더방지용
=> 본인의 스테이트가 바뀔 때는 재렌더 됨 - 함수형 컴포넌트에 업데이트 조건을 걸어줌 : 자식컴포넌트는 업데이트 조건에 따라서만 렌더링 되게 함
- 기본 사용 문법
const MyComponent = React.memo(function MyComponent(props) { /* props를 사용하여 렌더링 */ });
- 동일한 props로 동일한 결과를 렌더링 한다면 재실행 하지 않는다!
=> 마지막으로 렌더링 한 결과를 재사용함
- 동일한 props로 동일한 결과를 렌더링 한다면 재실행 하지 않는다!
예제
const CounterA = React.memo(({count}) => {
useEffect(()=>{
console.log(`CounterA Update - count: ${count}`)
})
return <div>{count}</div>
})
const CounterB = React.memo(({obj})=>{
useEffect(()=>{
console.log(`CounterB Update - count: ${obj.count}`)
})
return <div>{obj.count}</div>
})
const OptimizeTest = () => {
const [count, setCount] = useState(1);
const [obj, setObj] =useState({
count: 1,
});
return <div style={{ padding: 50 }}>
<div>
<h2>Counter A</h2>
<CounterA count={count}/>
<button onClick={() => setCount(count)}>A button</button>
</div>
<div>
<h2>Counter B</h2>
<CounterB obj={obj}/>
<button onClick={() => setObj({
count: obj.count,
})}>B button</button>
</div>
</div>
- CounterA는 prop으로 동일한 값을 줘서 재실행 되지 않음
- CounterB는 prop으로 객체를 줘서 얕은비교(객체 !== 객체)가 됨으로 재실행 됨
=> areEaual를 비교함수로 사용하여 한번 더 비교를 해줘야 함
=> obj.count의 값이 동일하면 true를 반환하기에 재실행되지 않음const areEqual = (prev, next) => { if(prev.obj.count === next.obj.count) { return true } return false } const MemoizedCounterB = React.memo(CounterB, areEqual)
🔽 useCallback
- 메모이제이션된 콜백을 반환 : useMemo와 비슷하게 동일한 작업을 방지하게 해주는 것
=> useMemo는 값을 반환해서 전달하지만, useCallback은 함수 자체를 전달
=>useCallback(fn, deps)
은useMemo(() => fn, deps)
와 같다
const onCreate = useCallback((author, content, emotion) => {
const created_date = new Date().getTime();
const newItem = {
author,
content,
emotion,
created_date,
id: dataId.current,
}
dataId.current += 1;
setData((data) => [newItem, ...data])
},[])
- Mount될 때 실행되는것을 마지막실행으로 기억하고 동일한 작업을 해야할 때 마지막실행을 가져다 씀
- 함수재생성 하면서 최신state 유지 : setData()에서 현재 data값을 담아 함수를 전달해줌으로써 onCreat가 변동사항 있을때에도 data의 유지가 가능
공부하며 정리&기록하는 ._. 씅로그
Author And Source
이 문제에 관하여(Hook - useMemo, React.memo, useCallback), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@sseung-i/React-최적화-방법저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)