コンポーネントの目的/サイズ/小道具/動作に基づいて、これら3つからどのように選択しますか?
カスタムメソッドを使用して拡張しReact.PureComponent
たりReact.Component
、カスタムshouldComponentUpdate
メソッドを使用して拡張したりすると、パフォーマンスに影響します。ステートレス機能コンポーネントの使用は「アーキテクチャ」の選択であり、そのままではパフォーマンスのメリットはありません(まだ)。
簡単に再利用する必要がある単純なプレゼンテーション専用コンポーネントの場合は、ステートレス機能コンポーネントをお勧めします。これにより、実際のアプリロジックから切り離され、テストが非常に簡単になり、予期しない副作用が発生しないことが確実になります。例外は、何らかの理由でそれらがたくさんある場合、またはそれらのレンダーメソッドを最適化する必要がある場合(shouldComponentUpdate
ステートレス機能コンポーネントを定義できないため)です。
PureComponent
出力が単純な小道具/状態に依存していることがわかっている場合は拡張してください(「単純」はネストされたデータ構造がないことを意味します。PureComponentは浅い比較を実行するためです)。また、パフォーマンスの向上が必要または可能です。
次/現在の小道具と状態の間のカスタム比較ロジックを実行してパフォーマンスを向上させる必要がある場合はComponent
、独自のものを拡張して実装しますshouldComponentUpdate
。たとえば、lodash#isEqualを使用して、深い比較をすばやく実行できます。
class MyComponent extends Component {
shouldComponentUpdate (nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
}
}
また、独自の実装shouldComponentUpdate
または拡張PureComponent
は最適化であり、通常どおり、パフォーマンスの問題がある場合にのみ調査を開始する必要があります(時期尚早な最適化は避けてください))。経験則として、私は常にこれらの最適化を、アプリケーションが動作状態になってから、ほとんどの機能がすでに実装されている状態で実行しようとしています。実際に邪魔になると、パフォーマンスの問題に集中する方がはるかに簡単になります。
もっと詳しく
機能的なステートレスコンポーネント:
これらは、関数を使用して定義されます。ステートレスコンポーネントには内部状態がないため、出力(レンダリングされるもの)は、この関数への入力として指定されたプロップにのみ依存します。
長所:
Reactでコンポーネントを定義する最も簡単な方法。状態を管理する必要がない場合は、なぜクラスと継承に悩むのでしょうか。関数とクラスの主な違いの1つは、関数を使用すると、出力が入力のみに依存することを確認できることです(以前の実行の履歴には依存しません)。
アプリで理想的には、できるだけ多くのステートレスコンポーネントを持つことを目指す必要があります。これは、通常、ロジックをビューレイヤーの外に移動し、それをreduxのようなものに移動したことを意味します。つまり、何もレンダリングせずに実際のロジックをテストできます。 (テストがはるかに簡単で、再利用性が高いなど)。
短所:
ライフサイクルメソッドはありません。componentDidMount
他の友達を定義する方法はありません。通常は、階層の上位にある親コンポーネント内で行うので、すべての子をステートレスな子に変えることができます。
を定義できないため、再レンダリングが必要になるタイミングを手動で制御する方法はありませんshouldComponentUpdate
。コンポーネントが新しい小道具を受け取るたびに再レンダリングが行われます(浅い比較などの方法はありません)。将来的には、Reactが自動的にステートレスコンポーネントを最適化できるようになります。現時点では、使用できるライブラリがいくつかあります。ステートレスなコンポーネントは単なる関数なので、基本的には「関数のメモ化」の典型的な問題です。
参照はサポートされていません:https : //github.com/facebook/react/issues/4936
PureComponentクラスを拡張するコンポーネントVS Componentクラスを拡張する通常のコンポーネント:
Reactは、構文PureRenderMixin
を使用して定義されたクラスに接続することができましたReact.createClass
。ミックスインはshouldComponentUpdate
、次の小道具と次の状態の間の浅い比較の実行を定義して、そこに変更があったかどうかを確認します。何も変化がなければ、再レンダリングを実行する必要はありません。
ES6構文を使用する場合は、ミックスインを使用できません。そのため、便宜上、React PureComponent
はを使用する代わりに継承できるクラスを導入しましたComponent
。と同じ方法でPureComponent
実装shouldComponentUpdate
するだけPureRendererMixin
です。現在/次の状態と小道具との浅い比較が、パフォーマンスを迅速に向上させる最も一般的なシナリオであるため、これは主に便利なものであるため、自分で実装する必要はありません。
例:
class UserAvatar extends Component {
render() {
return <div><img src={this.props.imageUrl} /> {{ this.props.username }} </div>
}
}
ご覧のとおり、出力はprops.imageUrl
およびに依存していprops.username
ます。親コンポーネントで<UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />
同じプロップでレンダリングした場合、Reactはrender
場合、出力がまったく同じであっても毎回れます。ただし、Reactはdom diffingを実装しているため、DOMは実際には更新されません。それでも、dom diffの実行はコストがかかる可能性があるため、このシナリオでは無駄になります。
場合UserAvatar
コンポーネントが延びるPureComponent
代わりに、比較浅いが行われます。また、propsとnextPropsは同じであるため、まったくrender
呼び出されません。
Reactの「純粋」の定義に関する注記:
一般に、「純粋な関数」は、同じ入力が与えられた場合に常に同じ結果に評価される関数です。出力(Reactの場合、それはrender
メソッドによって返されます)は、履歴/状態に依存せず、副作用(関数の外部の「世界」を変更する操作)もありません。
Reactでは、決して呼び出さthis.setState
ず、を使用しないコンポーネントを「ステートレス」と呼ぶ場合、ステートレスコンポーネントは必ずしも上記の定義に従って純粋なコンポーネントであるとは限りませんthis.state
。
実際、では、PureComponent
ライフサイクルメソッド中に副作用を実行することができます。たとえば、ajaxリクエストを内部に送信したり、componentDidMount
DOM計算を実行して内のdivの高さを動的に調整したりできますrender
。
「ダムコンポーネント」の定義には、(少なくとも私の理解では)より「実用的な」意味があります。ダムコンポーネントは、親コンポーネントがプロップを介して何をすべきかを「伝えられ」、方法を知らないがプロップを使用します代わりにコールバック。
「スマート」の例AvatarComponent
:
class AvatarComponent extends Component {
expandAvatar () {
this.setState({ loading: true });
sendAjaxRequest(...).then(() => {
this.setState({ loading: false });
});
}
render () {
<div onClick={this.expandAvatar}>
<img src={this.props.username} />
</div>
}
}
「ダム」の例AvatarComponent
:
class AvatarComponent extends Component {
render () {
<div onClick={this.props.onExpandAvatar}>
{this.props.loading && <div className="spinner" />}
<img src={this.props.username} />
</div>
}
}
最後に、「ダム」、「ステートレス」、および「ピュア」はまったく異なる概念であり、ほとんどの場合、ユースケースによっては重複する場合がありますが、必ずしもそうとは限りません。