[React] PureComponent, memo (+ 함수형 setState)

이호정·2022년 8월 17일
0

React

목록 보기
1/5

네이버 블로그에서 이전, 원글 작성일시 : 2021.07.14.20:49

ZeroCho님의 강의를 보면서 React를 공부하고 있다.
강의를 바탕으로 내가 이해한 그대로 정리할 예정이다.
중대한 오류나 지식 부족이 발견될 확률이 높으니 혹시 이 글을 보는 사람이 있다면 주의하시길..

React 기본 강좌 3-11. PureComponent와 React.memo

chrome의 React Developer tools 확장 프로그램을 이용하면
React로 만들어진 페이지를 이것저것 분석해볼 수 있다.


그 중에서도 Highlight updates when components render 옵션을 이용하면
말그대로 어떤 컴포넌트들이 업데이트 되는지 실시간으로 확인할 수 있다.


이를 이용해 불필요한 렌더링을 하지 않도록 하는 방법에 대해 배웠다.

render() {
        const {result, value, tries} = this.state;
        return (
            <>
                <h1>{result}</h1>
                <form onSubmit={this.onSubmitForm}>
                    <input ref={this.onRef} maxLength={4} value={value} onChange={this.onChangeInput} />
                    <button>입력!</button>
                </form>
                <div>시도: {tries.length}</div>
                <ul>
                    {tries.map((v, i) => {
                        return (
                            <Try key={`${i+1}차 시도:`} tryInfo={v} />
                        );
                    })}
                </ul>
            </>
        );
    }

기본적으로 React에서 컴포넌트들은 state와 props가 업데이트, 즉 변경될 때 다시 렌더링 된다.
위의 예시는 강의에서 작성한 간단한 숫자야구 컴포넌트의 render() 메소드 내용이다.
숫자야구 컴포넌트는 value, result, answer, tries 를 state로 가지고,
하위 Try 컴포넌트에게 배열인 tries의 요소를 props로 전달하고 있다.

위 상황에서, 이벤트 메소드에 value, result만 변경하는 setState 메소드가 호출될때
Try 컴포넌트는 다시 렌더링 될까? 확인해보면 다시 렌더링 된다.
이처럼 실질적으로 사용하는 state/props는 바뀌지 않는데 다시 렌더링 되면 낭비라고 볼 수 있다.
이를 해결하기 위한 방법을 몇가지 정리해본다.



1. React.Component의 shouldComponentUpdate(nextProps, nextState, nextContext) 메소드

어떤 경우에는 다시 렌더링하고, 어떤 경우에는 그대로 두는 등 내맘대로 조절 할 수 있다.
return이 true이면 렌더링해라, false면 렌더링하지 말라는 뜻이다.
보통 현재 state/props와 nextProps/nextState를 비교해 렌더링 유무를 조절한다고 한다.

const React = require('react');
const { Component } = React;

class HoJangMan extends Component {
    state = {
        count: 0
    };

    shouldComponentUpdate(nextProps, nextState, nextContext) {
        if(this.state.count === nextState.count) {
            return true;
        }
        return false;
    }

    render() {
        return ();
    }
}



2. class 기반 컴포넌트일 경우 PureComponent

const React = require('react');
const {PureComponent} = React;

class HoJangMan extends PureComponent {
    render() {
        return ();
    }
}

위와 같이 PureComponent를 상속하면 자동으로
현재와 과거의 state, props를 비교해서 렌더링 유무를 판별한다.
주의할 점은 객체나 배열처럼 참조를 이용하는 state/props들은 변경유무를 ===로 확인하기 때문에
값을 변경 시키고자 할때는 새로운 객체나 배열을 생성, 대입해줘야 한다.
(참조를 변경시켜야 한다는 뜻이다.)

특히 배열에 요소를 추가하는 경우 아래와 같이 작성하는 것을 권장한다.

this.setState({
    arr: [...arr, 1] //끝에 요소 추가
});



3. 함수형 컴포넌트일 경우 React.memo

함수형 컴포넌트에서는 PureComponent도 상속할 수 없고, shouldComponentUpdate도 사용할 수 없다.
이럴 때 사용하는 것이 바로 memo!

const React = require('react');
const { memo } = React;

const HoJangMan = memo(() => {
    return ();
})

위 예시처럼 기존에 만들었던 컴포넌트 전체를 memo()로 감싸주기만 하면 끝!


추가적으로 알아두면 좋을 사항은 함수형 setState 이다.
state를 변경하고자 할 때, 이전 state를 이용해 현재 state를 변경할 예정이라면
아래와 같이 함수형으로 작성하는것을 권장한다.

this.setState((prevState, prevProps) => {
    return {
        count: prevState.count + 1,
    }
});

setState에 객체를 인자로 줄 경우 비동기로 작동하기 때문에 순서를 보장하지 못하고,
순서가 필요한 로직의 경우 예상과는 다른 결과를 불러올 수 있다.

this.setState({ count: this.state.count+1 });
this.setState({ count: this.state.count+1 });
this.setState({ count: this.state.count+1 });

위와 같이 count를 1씩 올리는 setState 세번 호출 되고, 값을 확인해보면 +3 이아니라 +1 일 것이다.
자바스크립트에서 객체를 병합하거나 구성할 때, 중복된 key에 대해서는 마지막 값이 우선되기 때문이다.

하지만 함수형으로 작성하면, 해당 함수가 실행 큐에 순차적으로 쌓이게 되어 차례차례 실행 된다.
따라서 순서가 필요하거나, 이전 state/props를 이용하는 setState는 함수형으로 작성하도록 하자!



PureComponent 나 memo는 컴포넌트를 최대한 작은 단위로 쪼갠다음 이용하면 유용하다고 한다. 어떤 방법이 정답이다! 보다는 상황에 맞게 유연하게 적용할 수 있도록 손에 익혀놔야 겠다.

0개의 댓글