web-dev-qa-db-ja.com

機能的なステートレスコンポーネント、PureComponent、コンポーネント。違いは何ですか、そして何を使うべきですか?

React v15.3.0 から、 PureComponent と呼ばれる新しい基本クラスが PureRenderMixin に組み込まれていることがわかりました。私が理解していることは、フードの下ではこれはshouldComponentUpdateの中の小道具の浅い比較を採用しているということです。

Reactコンポーネントを定義するための3つの方法があります。

  1. クラスを拡張しない機能的なステートレスコンポーネント
  2. PureComponentクラスを拡張するコンポーネント
  3. Componentクラスを拡張する通常のコンポーネント

しばらく前に、ステートレスコンポーネントを純粋なコンポーネント、あるいはダムコンポーネントと呼ぶこともありました。 「純粋な」という言葉の定義全体がReactで変更されたようです。

私はこれら3つの基本的な違いを理解していますが、私はまだ 何を選択するのか /////// /確実ではないです/ /。また、それぞれのパフォーマンスへの影響とトレードオフは何ですか?


更新

これらは私が明確になることを期待する質問です:

  • 単純なコンポーネントを(単純化のために)機能的として定義するのか、(パフォーマンス上の理由から)PureComponentクラスを拡張するのかを選択する必要がありますか?
  • 私が失った単純さと本当のトレードオフを得ることでパフォーマンスが向上しますか?
  • パフォーマンスを向上させるために常にComponentを使用できる場合は、通常のPureComponentクラスを拡張する必要がありますか?
177
free-soul

コンポーネントの目的/サイズ/小道具/動作に基づいて、これら3つの中からどのように決定しますか?

カスタムshouldComponentUpdateメソッドを使用してReact.PureComponentまたはReact.Componentから拡張すると、パフォーマンスに影響があります。ステートレス機能コンポーネントの使用は「アーキテクチャ上」の選択であり、そのままではパフォーマンス上の利点はありません(まだ)。

  • 簡単に再利用する必要がある単純でプレゼンテーション専用のコンポーネントの場合は、ステートレス機能コンポーネントを使用します。こうすれば、実際のアプリロジックから切り離されていること、テストが簡単であること、予期しない副作用がないことを確認できます。例外は、何らかの理由でたくさんのがある場合、または実際にそれらのレンダリング方法を最適化する必要がある場合です(shouldComponentUpdateを定義できないため)。ステートレス機能コンポーネント)。

  • 出力が単純な小道具/状態(PureComponentが簡易比較を実行するため、入れ子になったデータ構造がないことを意味する "simple")に依存することがわかっている場合は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.createClass構文を使って定義されたクラスにアタッチできるPureRenderMixinを持っていたReact。 mixinは単に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.imageUrlprops.usernameに依存しています。親コンポーネント内で同じ小道具で<UserAvatar username="fabio" imageUrl="http://foo.com/fabio.jpg" />をレンダリングすると、たとえ出力がまったく同じであっても、Reactは毎回renderを呼び出します。ただし、ReactはDOM Diffingを実装しているため、DOMは実際には更新されません。それでも、ドーム拡散を実行することは費用がかかる可能性があるので、このシナリオではそれは無駄になるであろう。

UserAvatarコンポーネントが代わりにPureComponentを拡張すると、浅い比較が実行されます。そして小道具とnextPropsは同じなので、renderはまったく呼び出されません。

Reactにおける "pure"の定義に関する注意事項:

一般に、「純粋関数」とは、同じ入力が与えられたときに常に同じ結果に評価される関数です。出力(Reactの場合、renderメソッドによって返されるもの)は履歴や状態に依存せず、副作用(関数の外側の "世界"を変更する操作)もありません。 ).

Reactでは、this.setStateを呼び出さず、this.stateを使用しないコンポーネントを "stateless"と呼ぶ場合、ステートレスコンポーネントは必ずしも上記の定義に従った純粋なコンポーネントとは限りません。

実際、PureComponentでは、ライフサイクルメソッド中に副作用を実行できます。たとえば、componentDidMount内でajaxリクエストを送信したり、render内でdivの高さを動的に調整するためのDOM計算を実行することができます。

「ダムコンポーネント」の定義はもっと実用的な意味を持っています(少なくとも私の理解では):ダムコンポーネントはプロップを介して親コンポーネントによって何をすべきかを「教えられ」、使い方を知らないがプロップを使う代わりにコールバック。

"smart" 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>
    }
}

結局、「ダム」、「ステートレス」、「ピュア」はまったく異なる概念で、時には重複することもありますが、必ずしもそうとは限りませんが、主にあなたのユースケースによって異なります。

295
fabio.sussetto

私は反応する以上の天才ではありませんが、私の理解から私たちは以下の状況で各成分を使用することができます

  1. ステートレスコンポーネント - これらはライフサイクルを持たないコンポーネントなので、レンダリングなど親コンポーネントの繰り返し要素のレンダリングに使用する必要があります。情報を表示するだけのテキストリスト。実行するアクションはありません。

  2. 純粋なコンポーネント - これらはライフサイクルを持つ項目で、特定の小道具のセットが与えられたときには常に同じ結果を返します。これらのコンポーネントは、複雑な子要素を持たず、それ自体にのみ影響を与える操作を実行するために使用される結果のリストまたは特定のオブジェクトデータを表示するときに使用できます。このようなユーザーカードのリストまたは製品カードのリスト(基本的な製品情報)およびユーザーが実行できる操作のみが、クリックして詳細ページを表示するか、カートに追加することです。

  3. 通常のコンポーネントまたは複合コンポーネント - 複合コンポーネントという用語を使用しました。これらは通常ページレベルのコンポーネントであり、多くの子コンポーネントで構成されているためです。あなたはそれが与えられた状態で同じ結果をレンダリングすることを100%確信することができないようにそれ自身のユニークな方法でふるまう。私が通常言ったように、これらはコンテナコンポーネントとして使われるべきです

23
abhirathore2006
  • React.Componentはデフォルトの "normal"コンポーネントです。あなたはそれらをclassキーワードとextends React.Componentを使って宣言します。ライフサイクルメソッド、イベントハンドラ、そしてあらゆるメソッドを持つクラスとしてそれらを考えてください。

  • React.PureComponentは、propsstateの浅い比較を行う関数を使ってshouldComponentUpdate()を実装するReact.Componentです。コンポーネントに変更されたプロップまたはステートネストされたデータがあり、再レンダリングしたい場合は、forceUpdate()を使用する必要があります。そのため、小道具として渡したり、状態に設定した配列やオブジェクトが変更されたときに、コンポーネントを再レンダリングする必要がある場合、これらは素晴らしいものではありません。

  • 機能コンポーネントは、ライフサイクル機能を持​​たないものです。それらはおそらくステートレスですが、それらはとても素晴らしくてきれいなので、(React 16.8以降)フックを持っているので、まだステートを持つことができます。だから私はそれらが単なる「クリーンコンポーネント」だと思います。

1
believesInSanta