강의 유튜브 주소 :

https://www.youtube.com/watch?v=V3QsSrldHqI&list=PLcqDmjxt30RtqbStQqk-eYMK8N-1SYIFn

 

 

리액트 최적화를 알기 위해서는 렌더링되는 부분을 이해해야한다.

class함수는 render부분이 리렌더링되고 함수컴포넌트는 전체가 리렌더링이 된다.

 

import React, { Component } from 'react';

class Test extends Component{
    state = {
        counter : 0
    };

    onClick = () => { 
        this.setState({});
    };

    render(){
        return (
            <div>
                <button onClick={this.onCLick}>클릭</button>
            </div>
        );
    }
}

 

Test코드에서 버튼을 클릭하면 리렌더링이 될까??

onClick 함수에서 setState하고 있지만 state를 변경한게 없다면 리렌더링이 될까?

위 예제에서 버튼을 클릭했을때 변하는 state는 없어도 class는 리렌더링이 된다.

 

리액트는 Props와 State를 변경하게 되면 보통 리렌더링이 일어난다.

바꾸는 State가 없어도 SetState 함수를 호출하게되면 리렌더링이 일어나기 때문이다.

 

이때 class는 두가지의 방법으로 리렌더링을 막고 최적화를 할 수 있다.

 

React의 라이프사이클 ShouldComponentUpdate

 

예제

import React, { Component } from 'react';

class Test extends Component{
    state = {
        counter : 0
    };
	
    // 이부분!
    shouldComponentUpdate(nextProps, nextState){
        if(this.state.counter !== nextStaste.count){
            return true;
        }

        return false;
    }


    onClick = () => { 
        this.setState({});
    };

    render(){
        return (
            <div>
                <button onClick={this.onCLick}>클릭</button>
            </div>
        );
    }
}

 

리액트의 라이프 사이클인 shouldComponentUpdate를 추가한다.

shouldComponentUpdate 함수는 현재 state와 변경되는 state를 비교하여 리렌더링을 할 것인지를 결정하는데,

위의 코드에서 nextState가 변경되는 state이고 this.state가 현재 state이다.

코드의 반환 값이 true일 경우에 리렌더링이 일어나며 false일 경우에 리렌더링이 일어나지 않는다.

따라서 내부에 비교하는 코드를 추가하여 최적화를 할 수 있다.

 

pureComponent

만약에 ShouldComponentUpdate가 복잡하다고 느낄 때에는 간단히 pureComponent를 사용할 수 있다.

Component 대신에 PureComponent를 import하여 extends 다음에 적어준다.

import React, { PureComponent } from 'react';

class Test extends PureComponent{
// ...

이때 ShouldComponentUpdate를 작성해주지 않아도 리렌더링이 일어나지 않게되는데, 

그 이유는 PureComponent 내부에서 shouldComponentUpdate를 자동으로 구현하기 때문이다.

주의해야하는 점은 Props와 State를 비교하도록 구현이 되어있기는 하나 얕은 비교이기 때문에 복잡한 자료 구조일 경우에 의도치 않는 결과가 나올수도 있다.

(객체를 생성할 때 너무 복잡한 구조로 하는것도 좋지 않다.)

그리고 PureComponent 내부에서도 shouldComponentUpdate를 쓸 수 있다고한다.

 

SetState할 경우에 주의해줘야하는 부분이 있는데, 배열이나 객체같은 참조형타입의 불변성 유지이다.

만약 아래와 같이 배열에 push할 경우에는 기존 배열을 참조하고 있기 때문에 pureComponent가 변화를 알아차리기가 어렵다. 불변성을 유지하여 setState를 하자.

// (X)
setState({
	array : this.state.array.push(a)
});

// (O)
setState({
	array : [...this.state.array, a]
});

 

pureComponent가 자동으로 비교하니 shouldComponentUpdate를 안써도 되지않을까 하는데,

각각 필요할 때 사용해야한다.

복잡한 구조일때 정밀한 작업이거나 특정 state가 변경되어도 리렌더링을 방지하고 싶을 경우 shouldComponentUpdate를 통해 의도적으로 막을 수 있기 때문이다.

 

Class에서는 pureComponent나 shouldComponentUpdate를 통해 최적화를 하며 

 

Hooks에서는 memo(Memoization)를 사용하여 최적화한다.

memo는 고차 컴포넌트(Higher Order Component)이며 함수 컴포넌트다.

부모 컴포넌트에서 전달한 props의 변화에 의한 리렌더링을 방지할 때 사용한다.

useState나 useContext 훅을 사용하면 리 렌더링이 일어난다.

import React, { memo } from 'react';

const Test = memo() => {
// ... 

혹은

function Test() {
  return <div>Test이다.</div>;
}

const Memoized = memo(Test);

memo도 얕은 비교로 동작하기 때문에 복잡한 자료구조일 경우 원치않는 동작이 있을 수 있다.

만약 얕은 비교의 기본 동작이 아닌 다른 동작을 원할 경우 두번째 인자를 별도로 제공하면 된다.

function MyComponent(props) {
  /* props를 사용하여 렌더링 */
}
function areEqual(prevProps, nextProps) {
  /*
    nextProp가 prevProps와 동일한 값을 가지면 true를 반환하고, 
    그렇지 않다면 false를 반환!!
    shouldComponentUpdate와 반대로 동작한다.
  */
}
export default React.memo(MyComponent, areEqual);

 

"

pureComponent나 shouldComponentUpdate 그리고 memo는 모두 성능 최적화를 위해 사용한다. 

그렇기 때문에 단순히 렌더링을 방지하기 위해 사용하거나 성능적인 이점이 없다면 사용하지 않는것이 좋다.

"

 


예제 및 지식 참고
https://ko.reactjs.org/docs/react-api.html

+ Recent posts