자식 컴포넌트의 리렌더링을 방지하는 법

nearworld·2023년 12월 5일
0

리액트 기초

목록 보기
12/12

일반적으로 자식 컴포넌트를 렌더링하는 방법을 생각하면 아래 방식을 떠올립니다.

불필요한 리렌더링이 되는 경우

function App() {
  return <Parent />;
}
function Parent() {
  return <Child />
}
function Child() {
  console.log('child!');
  
  return <div>child</div>
}

위 방식의 경우에는 부모 컴포넌트인 Parent의 상태가 변경되어 Parent 컴포넌트가 리렌더링이 될 경우 Parent의 자식 컴포넌트인 Child 컴포넌트도 리렌더링이 되게 됩니다.

리렌더링을 일으키기 위해 상태를 사용하겠습니다.

function Parent() {
  const [state, setState] = useState(0);
  
  return <div onClick={() => setState(state + 1)}>
  	<Child />
    {state}
  </div>
}

onClick 이벤트 핸들러가 등록되어있는 div 태그를 클릭합니다.
그러면 {state} 부분이 웹 페이지에서 숫자로 1씩 증가하는 것을 볼 수 있을겁니다.
그리고 웹 브라우저의 콘솔창을 확인해보면 child!가 클릭시마다 찍히는 걸 볼 수 있습니다.

그런데 Child 컴포넌트는 아무런 변화가 없어서 리렌더링이 필요가 없는 상황입니다.
이게 가벼운 자식 컴포넌트면 성능상 문제가 되지는 않겠지만 상당히 헤비한 컴포넌트라면 불필요하게 리렌더링 되는 것은 문제가 될 수 있습니다. 그래서 이를 방지하기 위한 방법이 있는데 그건 자식 함수 컴포넌트를 prop으로 내리는 것입니다.

불필요한 리렌더링이 일어나지 않는 경우

Prop

function App() {
  return (
    <Parent child={<Child />} />
  )
}
function Parent({child}) {
  const [state, setState] = useState(0);
  
  return <div onClick={() => setState(state + 1)}>
    {child}
    {state}
  </div>
}

prop으로 내렸을 경우 리렌더링이 어떻게 되는지 보겠습니다.

Child 컴포넌트가 리렌더링이 되지 않는 것을 볼 수 있습니다.
그 이유는 리액트에서는 리렌더링시 함수 컴포넌트의 리턴 값을 비교하여 다른 부분들을 리렌더링하는데 prop으로 던져진 경우에는 상위 스코프의 객체를 참조하는 상황이 되기 때문에 Child는 여전히 같습니다.

이제 위 방식이 불필요한 리렌더링을 방지하는 방법이란 걸 알았습니다.
하지만 컴포넌트를 prop으로 내리는건 가독성 면에서도 좋지 않다고 생각이 듭니다.
그래서 코드를 더 개선해보자면 아래와 같습니다.

children prop

function App() {
  return (
    <Parent>
      <Child />
    </Parent>
  );
}
export const Parent = ({ children }) => {
  const [state, setState] = useState(0);

  return (
    <div onClick={() => setState(state + 1)}>
      {children}
      <p>{state}</p>
    </div>
  );
};

children도 prop이기 때문에 prop으로 컴포넌트를 내려준 것과 같은 상황이나 마찬가지입니다. 그래서 children으로 내리는 경우에도 불필요한 리렌더링을 방지할 수 있습니다.

profile
깃허브: https://github.com/nearworld

0개의 댓글