컴퓨터가 동일한 계산을 반복해야할 때, 이전에 계산한 값을 메모리에 저장하여 반복 수행을 줄이고 프로그램 실생 속도를 빠르게 하는 기술.
주로 알고리즘에서 동적 계획법 문제를 풀 때 자주 사용되는 구조이며, 이와 반대되는 개념으론 Tabulation(Bottom up) 이 있음. 전반적인 구조는 다음과 같이 이루어짐.
원치 않는 상황에서까지 컴포넌트가 리렌더링될 때 자원의 낭비를 막기 위해 사용
이 때 성능 최적화를 위해 사용되는 것이 useMemo.
import { useMemo, useState } from "react"
import "./App.css"
function App() {
const example = (users) => {
console.log("example 함수 실행")
return users.filter((user) => user).length
}
const [users, setUsers] = useState([false, false, false])
const [ex, setEx] = useState(false)
const handleClick = (i) => {
users[i] = !users[i]
setUsers([...users])
}
const handleInput = () => {
setEx(!ex)
}
// const check = example(users)
const check = useMemo(() => example(users), [users])
return (
<>
<h1>check circle +{check}</h1>
<input onInput={handleInput} type="text" />
{users.map((e, i) => {
return e ? (
<div key={i} onClick={() => handleClick(i)} className="red circle" />
) : (
<div key={i} onClick={() => handleClick(i)} className="blue circle" />
)
})}
</>
)
}
export default App
만약 useMemo를 하지 않은 상태에서 다음 코드를 실행하면 user의 갯수가 늘어나거나 줄어나는 상황과 관계 없는 상황에서도 count 함수가 실행되는 것을 확인 할 수 있음
useMemo(어떻게 연산할지 정의하는 함수, 의존성 배열(deps 배열))
ex)const check = useMemo(() => example(users), [users])
useMemo를 사용하면 의존성배열에 작성한 변수가 바뀌었을 때만 함수가 동작하고, 다른 이유로 재렌더링된다면 동작하지 않음.
useMemo와 비슷한 훅으로 useMemo가 결과값을 저장해 재사용한다면, useCallback은 함수를 재사용할 때 사용함. 함수들은 컴포넌트가 리렌더링 될 때마다 새로 만들어짐.
함수에서 사용되는 Props가 있다면 반드시 deps 배열안에 포함시켜야 함.
렌더링시 둘의 차이가 뚜렷하게 나타나지는 않음. 하지만 이렇게 함수를 최적화시켜야, props가 바뀌지 않았을 때 virtualDOM에 재렌더링이 되지 않도록 할 수 있음 -> React.memo
사용
useEffect와 비교했을 때 페이지가 처음 렌더링되는 시점에서 차이가 발생할 줄 알았으나, 실제로는 두 함수 모두 처음 렌더링되는 시점에서 실행되는 것처럼 보임.
useMemo는 local call로 이 컴포넌트로만 뭔가를 할 수 있음. useEffect는 collective call로 비동기던 아니던 모든 컴포넌트의 렌더링이 모두 끝난 후 이루어짐.
useMemo -> useLayoutEffect -> useEffect의 순으로 실행됨.
Memoization
을 위해 useMemo는 리턴값
을 저장해두고 필요할 때마다 꺼내서 사용함.
useCallback에서는 함수
를 저장해두고 사용. useEffect에서는 최적화가 이뤄지지 않는다.
React.memo
UI성능을 증진시키기 위해 React는 고차 컴포넌트(HOC) React.memo()
를 제공. React.memo()
로 래핑된 렌더링 결과를 저장해 다음 렌더링시 Props가 같다면 메모이징된 내용을 재사용해 불필요한 재렌더링을 막음. 함수형 컴포넌트에 적용됨.
props 혹은 props의 객체를 비교할 때 얕은 비교를 실행.
비교방식을 변경하고 싶다면 React.memo의 두번째 매개변수로 비교함수를 만들어서 넘겨주면 됨.
비교함수가 true를 반환한다면 두 객체가 같은 객체라고 판단함.
React.memo(component, [equalFuc(a, b)])
부모컴포넌트가 자주 재렌더링될 때, 자식 컴포넌트에 변함이 없는 경우 재렌더링이 일어나는 걸 막기 위해 자식 컴포넌트에 React.memo를 사용하는 것을 권장
위의 권장하는 상황이 아니라면 가급적 사용을 권장하지 않음.
클래스 기반의 컴포넌트에서 최적화가 필요하다면, PureComponent를 확장해 사용하거나 shouldComponentUpdate()메서드를 구현하는 걸 추천
props가 동일할 때 메모리 최적화가 발생하기 때문에 props가 자주 변경된다면 굳이 사용할 이유가 없음.
함수는 일반객체와 동일한 비교원칙을 따라 오직 자신과 자신을 비교했을 때만 동일 (true)
그래서 이때 사용되는게 useCallback()
useCallback()을 이용해 함수 인스턴스를 보존시켜 같은 함수가 반환될 수 있도록 함.
리액트 공부에 너무 도움이 되요!