1. ホーム
  2. javascript

[解決済み】Reactの機能的なステートレスコンポーネント、PureComponent、Component、どのような違いがあり、いつ何を使うべきですか?

2022-04-16 12:06:32

質問

から知ったのですが リアクトv15.3.0 という新しいベースクラスがあります。 ピュアコンポーネント で拡張し ピュアレンダーミキシン を組み込んでいます。私が理解しているのは、これはボンネットの中で shouldComponentUpdate .

これで、Reactコンポーネントを定義する方法が3つ揃いました。

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

少し前までは、ステートレス・コンポーネントのことをピュア・コンポーネント、あるいはダム・コンポーネントと呼んでいました。Reactでは、「純粋」という言葉の定義が変わったようです。

この3つの基本的な違いは理解していますが、まだよくわかりません。 いつ何を選択するか . また、それぞれのパフォーマンスへの影響やトレードオフはどのようなものでしょうか?


更新情報 :

これらの質問は、私が解明を期待しているものです。

  • シンプルなコンポーネントを機能的なものとして定義するか(シンプルにするため)、それとも PureComponent クラス(パフォーマンスのため)ですか?
  • を使用することで、パフォーマンスアップを実現することができます。 シンプルさが失われた?
  • を拡張する必要はありますか? Component クラスを使用することができます。 PureComponent を使えば、より良いパフォーマンスが得られるのでは?

解決方法は?

私たちの部品の目的/サイズ/小道具/動作に基づいて、この3つの中からどのように決めるか、どのように選ぶか?

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

  • 再利用が容易である必要がある、シンプルなプレゼンテーション専用のコンポーネントには、ステートレス関数型コンポーネントが適しています。こうすることで、実際のアプリのロジックから切り離され、テストが非常に簡単になり、予期せぬ副作用がないことを確認できます。例外は、何らかの理由で たくさん を定義することができないため)、レンダリングメソッドを最適化する必要がある場合です。 shouldComponentUpdate は、ステートレスな関数型コンポーネントのためのものです。)

  • エクステンド PureComponent 出力が単純なpropやstateに依存することがわかっていて(PureComponentは浅い比較を行うので、ネストしたデータ構造がないことを意味します)、いくつかのパフォーマンス向上が必要/可能であれば。

  • 拡張 Component を実装し、独自の shouldComponentUpdate もし、next/current props と state の間のカスタム比較ロジックを実行してパフォーマンスを向上させる必要がある場合。例えば、lodash#isEqualを使えば深い比較を素早く行うことができます。

    class MyComponent extends Component {
        shouldComponentUpdate (nextProps, nextState) {
            return !_.isEqual(this.props, nextProps) || !_.isEqual(this.state, nextState);
        }
    }
    
    

また、自分で実装した shouldComponentUpdate を拡張したものです。 PureComponent は最適化であり、通常通り、パフォーマンスに問題がある場合にのみ検討を開始すべきです ( 早すぎる最適化を避ける ). 経験則として、私はいつも、アプリケーションが動作する状態になり、ほとんどの機能がすでに実装された後で、これらの最適化を行うようにしています。パフォーマンスの問題は、実際に邪魔になったときに焦点を当てる方がずっと簡単だからです。

詳細

機能的なステートレス・コンポーネント。

これらは、単に関数を使って定義されています。ステートレス・コンポーネントは内部状態を持たないので、出力(レンダリングされるもの)はこの関数への入力として与えられたpropsにのみ依存します。

長所

  • Reactでコンポーネントを定義する最もシンプルな方法です。状態を管理する必要がないのであれば、なぜわざわざクラスや継承を使うのか?関数とクラスの主な違いは、関数では出力が入力にのみ依存することが確実なことです(以前の実行の履歴には依存しない)。

  • なぜなら、それは通常、ロジックをビューレイヤーの外に移動し、reduxのようなものに移動したことを意味するからです。つまり、何もレンダリングせずに実際のロジックをテストすることができます(より簡単にテストでき、より再利用できるなど)。

短所

  • ライフサイクルメソッドがない。を定義する方法がない componentDidMount といった仲間たちがいます。通常は、より高い階層の親コンポーネントの中でそれを行い、すべての子をステートレスにすることができます。

  • を定義できないので、再レンダリングが必要なときに手動で制御する方法がありません。 shouldComponentUpdate . コンポーネントが新しいプロップを受け取るたびに、再レンダリングが発生します(浅い比較などを行う方法はありません)。将来的には、Reactはステートレスコンポーネントを自動的に最適化することができますが、現時点では、いくつかのライブラリを使用することができます。ステートレス・コンポーネントは単なる関数なので、基本的には "関数のメモ化" の古典的な問題です。

  • Refはサポートされていません。 https://github.com/facebook/react/issues/4936

PureComponent クラスを継承したコンポーネント VS Component クラスを継承した通常のコンポーネント。

Reactでは以前は PureRenderMixin を使用して定義されたクラスにアタッチすることができます。 React.createClass の構文があります。ミキシンは単に shouldComponentUpdate は、次の props と次の状態を浅く比較し、そこで何かが変更されたかどうかをチェックすることを実行します。もし何も変更がなければ、再レンダリングを行う必要はありません。

ES6の構文を使いたい場合、mixinは使えません。そこで、Reactは利便性を高めるために PureComponent を使用する代わりに、継承することができます。 Component . PureComponent を実装しているだけです。 shouldComponentUpdate と同じように PureRendererMixin . 現在の状態/次の状態とpropsの浅い比較は、おそらく最も一般的なシナリオであり、いくつかの迅速なパフォーマンスの勝利を与えることができるので、これはほとんど便利なもので、自分でそれを実装する必要はありません。

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" /> を同じpropsで呼び出すと、Reactは render は毎回、たとえ出力がまったく同じであっても、です。しかし、Reactはdom diffingを実装しているので、DOMは実際には更新されないことを忘れないでください。それでも、dom diffing の実行にはコストがかかるので、このシナリオでは無駄になってしまいます。

もし UserAvatar コンポーネントが拡張する PureComponent の代わりに、浅い比較が実行されます。また、propsとnextPropsが同じであるため render は全く呼ばれない。

Reactにおける"pure"の定義に関する注意点。

一般に、quot;pure function"とは、同じ入力があれば常に同じ結果に評価される関数のことを指します。出力(Reactの場合、これは render メソッド) は履歴や状態に依存せず、副作用 (関数の外側で "world" を変更する操作) を持ちません。

Reactでは、ステートレス・コンポーネントは必ずしも上記の定義に従った純粋なコンポーネントではありません。 this.setState を使用せず、かつ this.state .

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

Dumb components" の定義には、(少なくとも私の理解では)より実用的な意味があります。Dumb components "gets told" what to do by a parent component via props, and doesn't know how to do things but used props callbacks instead.

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

例:"dumb" AvatarComponent :

class AvatarComponent extends Component {
    render () {
        <div onClick={this.props.onExpandAvatar}>
            {this.props.loading && <div className="spinner" />}
            <img src={this.props.username} />
        </div>
    }
}

最終的には、「ダム」、「ステートレス」、「ピュア」はそれぞれまったく異なる概念であり、ユースケースによって重なる場合もありますが、必ずしもそうとは限りません。