성능을 유지하려면 render 메서드에서 새로운 엔티티 생성을 고려해야합니다.
순수 렌더란?
리액트의 순수 렌더링이란 얕은 동등성 검사로 shouldComponentUpdate 메서드를 구현하는 구성 요소를 의미합니다.
이것의 예로는 React.PureComponent, PureRenderMixin, recompose/pure 등이 있습니다.
class Table extends PureComponent {
render() {
return (
<div>
{this.props.items.map((i) => (
<Cell data={i} options={this.props.options || []} />
))}
</div>
);
}
}
** 이 문제(issue)는 {this.props.options || []}
에 있습니다. - 이것은 단일 셀 변경에도 모든 셀이 다시 렌더링됩니다. 왜일까요?**
옵션 배열(this.props.options)이 Cell 요소 아래로 전달 된 것을 볼 수 있습니다. 일반적으로 이것은 문제가되지 않습니다. 다른 Cell 요소는 값싼 얕은 동등성 검사를 수행 할 수 있기 때문에 다시 렌더링되지 않습니다.
렌더링을 완전히 건너 뛰지만, 이 경우 options prop은 null이고 기본 배열이 사용되었기 때문에 아시다시피 배열 리터럴은 새 배열 인스턴스를 만드는 new Array ()와 동일합니다.
이것은 Cell 요소 내부의 모든 순수한 렌더링 최적화를 완전히 파괴(destroyed)했습니다. Javascript에서는 인스턴스마다 식별자(identity)가 다르므로 항상 얕은 동등성 검사(shallow equality check)가 수행됩니다. 검사 이후 false를 생성하고 리액트에게 컴포넌트를 다시 렌더링하도록 지시합니다.
const defaultval = []; // <--- 수정 사항 (defaultProps도 사용되었을 수 있음).
class Table extends PureComponent {
render() {
return (
<div>
{this.props.items.map((i) => (
<Cell data={i} options={this.props.options || defaultval} />
))}
</div>
);
}
}
render()에서 함수를 사용하는 것과 유사한 문제
class App extends PureComponent {
render() {
return <MyInput onChange={(e) => this.props.update(e.target.value)} />;
}
}
class App extends PureComponent {
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update.bind(this)} />;
}
}
^^ 두 경우 모두 새로운 식별자(identity)로 새로운 기능이 생성됩니다. 배열 리터럴과 같습니다. 함수를 먼저(early) 바인딩해야 합니다.
class App extends PureComponent {
constructor(props) {
super(props);
this.update = this.update.bind(this);
}
update(e) {
this.props.update(e.target.value);
}
render() {
return <MyInput onChange={this.update} />;
}
}
class Component extends React.Component {
state = {clicked: false};
onClick() {
this.setState({clicked: true})
}
render() {
// 렌더링 할 때마다 생성 될 옵션 개체, 설정되지 않은 경우 {test: 1}로 새로이 할당
const options = this.props.options || {test: 1};
return <Something
options={options}
// 렌더마다 생성되는 새로운 기능
onClick={this.onClick.bind(this)}
// 렌더마다 생성되는 새로운 기능과 클로저
onTouchTap={(event) => this.onClick(event)
/>
}
}
class Component extends React.Component {
state = { clicked: false };
options = { test: 1 };
onClick = () => {
this.setState({ clicked: true });
};
render() {
// 렌더링 시 한 번 생성된 옵션 개체
const options = this.props.options || this.options;
return (
<Something
options={options}
onClick={this.onClick} // 렌더링 시 한 번 생성된 함수, 한 번만 바인딩 됨
onTouchTap={this.onClick} // 렌더링 시 한 번 생성된 함수, 한 번만 바인딩 됨
/>
);
}
}