-
알았는데 까먹은 React 기록 - useMemo vs useCallback이해를 위한 기록들 2023. 1. 5. 22:40
시작하며
매번 헷갈리는 useMemo, useCallback 이번 포스팅으로 머리에 타투로 새긴다.
메모이제이션
- 수행한 연산값을 저장해두고 재사용함으로 중복연산을 피해서 성능 최적화를 할 수 있는 방법
- useMemo와 useCallback 모두 메모이제이션을 위한 최적화를 위해 사용한다.
리엑트에서 re-render하는 경우
- 자신의 state가 변경된 경우
- 부모로부터 받은 props가 변경 될 경우
- 부모 컴포넌트가 리렌더링 될 때
useMemo: 값을 메모이제이션
useMemo(()=>fn, deps)
- deps가 변할 때만 fn을 실행시켜서 값을 반환한다.
useCallback: 함수를 메모이제이션
useCallback(fn, deps)
- 함수와는 상관없는 값이 변할 때 함수 컴포넌트가 불필요하게 업데이트 하는 것을 방지한다.
- 잘못 deps를 설정할 경우 내가 업데이트를 하기 원하는 값이 업데이트가 되지 않을 수 있으니 주의해야 한다.
- 완전히 참조 값이 다른 새로운 함수를 반환한다.
React.memo()
function Counter({count}) { return ( <h1>{count}</h1> ) } export default React.memo(Counter)
- react가 컴포넌트를 렌더링한 경과를 메모라이징해서 다음 re-render시에 props가 같은 경우 memo된 내용을 재사용한다.
- 항상 동일한 참조값을 리턴
useMemo나 useCallback을 사용하면 안되는 경우
- deps에 완전히 새로운
useMemo나 useCallback을 사용해야 하는 경우
- 계산 비용이 많이 들고 map, filter 등을 사용하는 경우와 같이 렌더링 이후에 도 동일할 가능성이 있는 경우
- 자식 컴포넌트에서 useEffect가 반복적으로 실행되는 것을 막고 싶은 경우
- 매우 큰 리엑트 트리에서 부모의 리렌더가 다른 전파를 막고 싶은 경우
useMemo, useCallback 사용 전
input에 있는 값을 변경했는데 props의 변화가 전혀없는 위에 있는 숫자가 변경된다. 이렇게 작은 기능이면 괜찮지만 크기가 큰 웹사이트에 매번 이런식으로 re-render가 되는 것은 성능에 좋지 않을 것이다.
useMemo, useCallback 사용 후
상황에 따라 너무 최적화를 하려다가 오히려 리렌더해야하는 컴포넌트를 생략하는 경우도 생길 수 있을 것 같아 사용할 때 주의해야겠다.
input 텍스트 변경에 따른 count의 re-rendering은 text, input을 컴포넌트로 묶어서 state와 함수를 묶는 것으로 해결하였다.
const LearnUseMemo = () => { const [name, setName] = useState<string>('') return ( <> <Counter/> {/* //Before <Name name={name}/> <input type="text" value={name} onChange={(e:ChangeEvent<HTMLInputElement>)=>setName(e.target.value)} placeholder='write' /> */} <Name/> </> ) } const Name = React.memo(() => { const [name, setName] = useState<string>('') return ( <> <h1>{name}</h1> <input type="text" value={name} onChange={(e:ChangeEvent<HTMLInputElement>)=>setName(e. target.value)} placeholder='write' /> </> ) }) export default LearnUseMemo;
count 기능에 대해서도 + 버튼이 매번 클릭될 때마다 re-render 되는 것을 useCallback을 통해 최초 선언된 함수가 메모되어서 계속 사용될 수 있게 하였다.
const Counter = () => { const [count,setCount] = useState<number>(0) const handleClick = useCallback(()=>setCount(count=>count+1),[]) return ( <div> <h1>{count}</h1> <Button onClick={handleClick}/> </div> ) }; export default Counter;
type ButtonProps = { onClick: ()=>void } const Button = ({onClick}:ButtonProps) => { return <button onClick={onClick}>+</button> } export default React.memo(Button);
'이해를 위한 기록들' 카테고리의 다른 글
Skeleton UI 적용기 (0) 2023.01.11 프론트엔드 네이밍 규칙(with 코딩 컨벤션) (0) 2023.01.07 드디어 정규 표현식 (0) 2022.12.22 jest 기초 (0) 2022.12.12 React Suspense 적용기 (0) 2022.12.11