본문 바로가기
공부/React

2022.08.21 - optimizing performance성능 최적화

by 기묜몬 2022. 8. 21.

** 리액트는 필요할때만 랜더한다. 

- reconciliation 재조정

리액트는 컴포넌트에서 prop이나 state가 변경될 때, 직전에 렌더링된 요소(element)와 새로 반환된 요소를 비교하여 실제 DOM을 업데이트 할지 말지 결정해야 한다. 이때 두 element가 일치하지 않으면 리액트는 새로운 요소로 DOM을 업데이트 하는데, 이러한 프로세스를 reconciliation이라고 한다.

 

- dom 엘리먼트의 타입이 다른 경우: 이전 트리를 버리고 완전히 새로운 트리를 구축
- dom 엘리먼트의 타입이 같은 경우: 두 엘리먼트의 속성(attribute)을 확인하여, 동일한 내역은 유지하고 변경된 속성들만 업데이트 한다. 

 

1. 자식에 대한 재귀적 처리 

DOM 노드의 자식들을 재귀적으로 처리할 때, React는 기본적으로 동시에 두 리스트를 순회하고 차이점이 있으면 변경된 부분을 갱신한다

// 이전 트리
<ul>
  <li>first</li>
  <li>second</li>
</ul>

// 새로운 트리
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

-> 위에서 아래로 비교하다가 third가 새로 생겼으므로 third 만 트리에 추가한다.

만약, third가 맨 앞에 추가되었다면 아래의 요소들이 같음에도 불구하고, 위에서부터 트리를 하나씩 갈아치운다. 

이런 문제를 해결하기 위해서 key속성을 제공한다. 

 

2.shouldComponentUpdate (랜더 그만시키기!!)

 

**리액트는 언제 렌더링을 수행하는가 ?
1) props가 변경 되었을때
2) state가 변경 되었을때
3) 부모 컴포넌트가 렌더링 되었을때

 

=> 1번의 예시 처럼 부모 컴포넌트에서 상태를 변경하였지만 그 영향을 받지 않는 자식 컴포넌트
또한 불필요한 렌더링을 수행하여 성능 손실이 발생하게 된다.

이럴 때 사용하는 것이 바로 SCU라는 라이프사이클 메서드이다.

* 조건에 따라 데이터가 변경되어 영향을 받아 렌더링이 필요한 경우에만 렌더링 작업을 수행할 수 있다.

  shouldComponentUpdate(previousProps) {
    for (const key in this.props) {
      if (previousProps[key] !== this.props[key]) {
        return true;
      }
    }
    return false;
  }

-> shouldComponentUpdate로 로직을 작성해서 동작하는 방법도 좋지만 해당 로직을 제공해주는

리액트 컴포넌트 PureComponent가 있다.

React.Component 대신 React.PureComponent를 사용하면 됨.

 

-> 함수형 컴포넌트의 경우 props가 같을때 리랜더를 하지 않게 하기 위해서는 화살표 함수로 바꾼 뒤 그대로 감싸서

React.memo라고 하는 함수로 실행해 준 다음 결과를 person이라는 컴포넌트로 사용하게 되면

memo라고 함수가 shouldComponentUpdate를 PureComponent처럼 바꿔서 사용하게 하는 역할을 한다. 

//(1)
function Person({ name, age }) {
  console.log("person render");
  return (
    <div>
      {name} / {age}
    </div>
  );
}
//(2) 화살표 함수로 변경
const Person = ({ name, age }) => {
  console.log("person render");
  return (
    <div>
      {name} / {age}
    </div>
  );
}
//(3) 코드 감싼 뒤 react.memo 함수로 실행 
const Person = React.memo(({ name, age }) => {
  console.log("person render");
  return (
    <div>
      {name} / {age}
    </div>
  );
});