이번에는 useMemo, useCallback에 대해서 배웠다.
useMemo는 "memoized" 를 의미하는데 이는, 이전에 계산 한 값을 재사용한다는 의미를 가지고 있다.
useMemo의 첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를 넣어주면 되고 두번째 파라미터에는 deps 배열을 넣어주면 되는데, 이 배열 안에 넣은 내용이 바뀌면, 우리가 등록한 함수를 호출해서 값을 연산해주고, 만약에 내용이 바뀌지 않았다면 이전에 연산한 값을 재사용하게 된다.
function activeUserCount(users) {
console.log('활성 사용자 수를 세는중...');
return users.filter(user => user.active).length;
}
const count = useMemo(() => activeUserCount(users), [users]);
위와 같이 작성할 때 deps로 전달해 준 users의 내용이 바뀔때 등록한 함수가 호출해서 연산된다. 그래서 예를 들어 input 박스의 value가 변경되어 리렌더링 될 때 위 함수는 실행이 안되게 해줄 수 있다. 이로써 어느정도 최적화를 진행한다.
useMemo 는 특정 결과값을 재사용 할 때 사용하는 반면, useCallback 은 특정 함수를 새로 만들지 않고 재사용하고 싶을때 사용한다.
컴포넌트 내에서 onChange, onCreate, onRemove 등과 같은 함수를 만들면 이 함수들은 그 컴포넌트가 리렌더링 될 때 다시 새로 만들어진다. 함수를 선언하는 것 자체는 사실 메모리도, CPU 도 리소스를 많이 차지 하는 작업은 아니기 때문에 함수를 새로 선언한다고 해서 그 자체 만으로 큰 부하가 생길일은 없지만, 한번 만든 함수를 필요할때만 새로 만들고 재사용하는 것이 중요하다고 한다.
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [users, username, email]);
위와 같이 작성할 때 useCallback안에서 쓸 함수나 props가 있다면 deps로 전달해줘야 한다.만약에 deps 배열 안에 함수에서 사용하는 값을 넣지 않게 된다면, 함수 내에서 해당 값들을 참조할때 가장 최신 값을 참조 할 것이라고 보장 할 수 없기 때문이라 한다. props 로 받아온 함수가 있다면, 이 또한 deps 에 넣어줘야 한다.
위 예제처럼 작성할 때 dependency에 넣은 배열 데이터가 변결 될 때 재사용되는 것은 맞지만, 안에 users가 변경될 때 함수가 새로 만들어진다.(당연히)
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users => users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [username, email]);
그래서 위와 같이 setUsers에 함수형 업데이트를 적용하면 users가 최신 값을 얻어올 수 있기 때문에 deps에 users를 지워도 된다.
앞에 hooks들은 컴포넌트의 상태, props, 함수의 재사용성을 조작한 것 이라면 React.memo는 리렌더링을 방지하여 컴포넌트의 리렌더링 성능 최적화를 해줄 수 있다.
그러나, 렌더링 최적화 하지 않을 컴포넌트에 React.memo 를 사용하는것은, 불필요한 props 비교만 하는 것이기 때문에 실제로 렌더링을 방지할수있는 상황이 있는 경우에만 사용 하는것을 추천한다.