리액트의 리렌더링에 대한 공부를 하던 중 React.memo라는 hoc을 발견해 자세히 알아보고자 한다.
- props의 변경
- state의 변경
- 부모 컴포넌트의 렌더링
3가지 조건 중에 부합한다면 리렌더링이 일어나게 된다.
React.memo는 HOC(고차 컴포넌트)이다.
HOC란 컴포넌트를 인자로 받아서 새로운 컴포넌트를 리턴해주는 함수이다.
컴포넌트를 React.memo()로 감싸주면 리액트는 컴포넌트를 렌더링하고 결과를 메모이징한다. 그리고 다음 렌더링이 일어날 때 props가 같다면, 리액트는 컴포넌트를 다시 렌더링 하지 않고 메모이징된 내용을 재사용한다.
import React from "react";
const Test = () => {
console.log("render");
return <h1>Test</h1>;
};
export default React.memo(Test);
위 코드와 같이 함수형 컴포넌트를 React.memo를 사용해 감싸줄 수 있다.
import React, { memo } from "react";
const Test = memo(() => {
console.log("render");
return <h1>Test</h1>;
});
export default Test;
혹은 import해서 이렇게도 선언 가능하다.
해당 컴포넌트는 memo로 감싸져 있기 때문에 리액트가 초기를 제외하고 state가 바뀌거나 부모 컴포넌트가 렌더링 되더라도 리렌더링 하지 않는다.
초기에 렌더링 하고 아무리 state를 변경해도 콘솔에 찍히지 않는다.
import React from "react";
const Test = (props) => {
console.log("render");
return <h1>{props.todoTitle}</h1>;
};
export default React.memo(Test);
부모 컴포넌트에는 todoTitle이라는 값을 useState로 선언하고 input에 onChange로 Eventlistner을 걸어주었다.
input 태그에 값을 입력해 글자 수 만큼 7번의 리렌더링이 일어났지만
다른 state가 변경 되거나 부모 컴포넌트가 리렌더링 되어도 해당 컴포넌트는 memo로 감싸주었기 때문에 리렌더링이 일어나지 않았다.
React.memo가 props 또는 props의 객체를 비교할 때 얕은 비교(shallow compare)로 비교를 한다.
여기서 얕은 비교란 원시 타입(number, string, boolean 등) 값은 실제 값이 동일한가를 비교하지만, 참조 타입(object, array, function 등)의 경우 원시 타입 값과 다르게 같은 값을 참조(reference) 하고 있는지를 비교 하는 것을 말한다.
그래서 비교 방식으로 커스텀을 하고자 한다면 React.memo의 두번째 인자에 함수를 넣어주면 된다.
import React from "react";
const Test = (props) => {
console.log("render");
return <h1>{props.todoTitle}</h1>;
};
export default React.memo(Test, (props) => props.todoTitle === "abcd");
props로 받은 todoTitle 값이 "abcd"와 일치하지 않으면 리렌더링을 하지 않게 코드를 작성해 보았다.
input에 abcd를 입력해 총 4번의 리렌더링이 일어났고
그 후에 글자를 더 입력해 보았지만 React.memo의 두번째 인자 값에 들어간 함수가 true를 리턴하게 되었기 때문에 더 이상 리렌더링이 일어나지 않는다.
즉 React.memo의 두번째 인자 값에 들어간 함수가 true를 리턴할때까지 리렌더링을 하다가 값이 false가 되면 리액트가 메모이징을 해 컴포넌트를 재사용한다.