Reactコンポーネントの設計と分解思考


以前にいくつかのReact技術スタックに関する記事を共有しました.
  • Uberモバイルのウェブページのバージョンをしますまだ十分ではない極致の性能はやっと本物の章の
  • に会います.
  • 解析Twitter先端アーキテクチャ学習複雑なシーンデータ設計
  • React Conf 2017乾物まとめ1:React+ES next=♥
  • React+Reduxが作成した「NEWS EARLY」の単一ページにプロジェクトを適用して、最前線技術スタックの真の意味を理解します.
  • react+redux工程例
  • 今日はまた、Reactコンポーネントの設計について興味深い話題を紹介します.
    Reactユニットは魔力が無限で、柔軟性も抜群です.私たちはコンポーネントのデザインにいろいろな種類を回して遊ぶことができます.しかし、保証コンポーネントのSingle reponsibility prnciple:単一の原則は非常に重要であり、それは私たちのコンポーネントをより簡単に、より便利に維持することができます.
    しかし、機能が複雑でふくよかなReactコンポーネントをどう分解するかは、簡単なことではないかもしれない.本稿では,浅い深さから,三つのReactコンポーネントを分解する方法を紹介する.
    カットレンダー()方法
    これは最も容易に考えられる方法である.一つのコンポーネントが多くの要素をレンダリングする場合、これらの要素を分離するレンダリングロジックを試みる必要がある.最も迅速な方法は、複数のsub-render方法を切断することです.
    次の例を見ると、より直感的になります.
    class Panel extends React.Component {
      renderHeading() {
        // ...
      }
    
      renderBody() {
        // ...
      }
    
      render() {
        return (
          
    {this.renderHeading()} {this.renderBody()}
    ); }
    注意深い読者はすぐに発見することができますが、実はこれはコンポーネント自体を分解していません.このPanelコンポーネントは元のstate、props、およびclass methodsを維持しています.
    複雑さを減らすにはどうすればいいですか?私たちはいくつかのサブコンポーネントを作成する必要があります.この時、最新版のReactを使ってサポートして推薦する関数式のコンポーネント/無状態のコンポーネントはきっといい試みです.
    const PanelHeader = (props) => (
      // ...
    );
    
    const PanelBody = (props) => (
      // ...
    );
    
    class Panel extends React.Component {
      render() {
        return (
          
    // Nice and explicit about which props are used
    ); } }
    前の方式と比べて、この微妙な改善は革命的です.二つのユニットコンポーネントを新規に作成しました.PanelHeaderとPanelBodyです.このようにテストの便利さをもたらしました.私たちは直接に異なるコンポーネントを分離してテストすることができます.同時に、Reactの新しいアルゴリズムエンジンReact Fiberによって、二つのユニットのコンポーネントはレンダリングの効率において、大幅な向上が期待される.
    モジュール
    問題の起点に戻ると、なぜ一つの部品がぶくぶくして複雑になるのですか?一つはレンダリング要素が多く、ネストされています.また、コンポーネントの内部変化が多い、または複数のconfigrationsがある場合です.
    この時点で、私たちはコンポーネントをモデルに変換することができます:親のコンポーネントは、様々なconfigrationsに焦点を当てています.
    やはり例を挙げて、このように理解するのが更にはっきりしています.
    たとえば、私たちはCommentコンポーネントを持っています.このコンポーネントには様々な行動やイベントがあります.コンポーネントによって表示される情報は、ユーザーのアイデンティティによって変化します.ユーザーがこのコメントの著者であるかどうか、このコメントが正しく保存されているかどうか、さまざまな権限が異なります.この時、すべてのロジックを混同するよりも、Reactを利用してReact elementの特性を伝達することができるかもしれません.私達はReact elementをコンポーネント間で伝達します.このようにして、一つのモデルのようになります.
    class CommentTemplate extends React.Component {
      static propTypes = {
        // Declare slots as type node
        metadata: PropTypes.node,
        actions: PropTypes.node,
      };
      
      render() {
        return (
          
    // Slot for metadata {this.props.metadata} // Slot for actions {this.props.actions}
    ...
    この時、私達の本当のCommentコンポーネント組織は以下の通りです.
    class Comment extends React.Component {
      render() {
        const metadata = this.props.publishTime ?
           :
          Saving...;
        
        const actions = [];
        if (this.props.isSignedIn) {
          actions.push();
          actions.push();
        }
        if (this.props.isAuthor) {
          actions.push();
        }
        
        return ;
      }
      
    metadataとactionsは、特定の場合にレンダリングが必要なReact elementである.
    例えば、this.props.publishTimeが存在するなら、metadataはそうです.どうせSavingです.
    ユーザーが登録されている場合はレンダリング(すなわち、actions値が)と、著者自身であればレンダリングが必要なコンテンツが追加されます.
    高次コンポーネント
    実際の開発では、コンポーネントはしばしば他の需要に汚染されます.
    例えば、私達はページの中ですべてのリンクのクリック情報を統計したいです.リンクをクリックしたときに、このページのdocumentのID値を含めて統計要求を送ります.一般的なアプローチは、Dockmentコンポーネントのライフサイクル関数componentDidMountとcomponentWillUnmountにコード論理を追加することです.
    class Document extends React.Component {
      componentDidMount() {
        ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
      }
      
      componentWillUnmount() {
        ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
      }
      
      onClick = (e) => {
        if (e.target.tagName === 'A') { // Naive check for elements
    sendAnalytics('link clicked'は、
    documentId:this.props.documentId/Specific information to be sent
    }
    )
    }
    レンダー(){
    //…
    このようにするいくつかの問題は:
  • 関連コンポーネントDockmentは、自身の主要なロジックを除いて、ホームページの表示以外に、他の統計ロジックが追加されました.
  • Dockmentコンポーネントのライフサイクル関数に他のロジックが存在すると、このコンポーネントはよりあいまいで不合理になる.
  • 統計論理コードは多重化できません.
  • コンポーネントの再構成、維持はより困難になります.
  • この問題を解決するために,高次コンポーネントという概念を提案した:higher-order components(HOCs).この名詞を難解に説明しないで、高次のコンポーネントを使って上のコードを再構成する方法を直接見てみます.
    function withLinkAnalytics(mapPropsToData, WrappedComponent) {
      class LinkAnalyticsWrapper extends React.Component {
        componentDidMount() {
          ReactDOM.findDOMNode(this).addEventListener('click', this.onClick);
        }
    
        componentWillUnmount() {
          ReactDOM.findDOMNode(this).removeEventListener('click', this.onClick);
        }
    
        onClick = (e) => {
          if (e.target.tagName === 'A') { // Naive check for elements
    const data=mapPropTodata?mapPropToData(this.props):{}
    sendAnalytics('link clicked',data);
    )
    }
    レンダー(){
    //Simply render the Wrapped Component with all props
    return;
    )
    )
    注意したいのは、withLink Analytics関数は、WrappedComponentコンポーネント自体を変更することはなく、Wrapped Componentコンポーネントの動作を変更することはありません.小包の新しいコンポーネントを返しました.実際の使い方は:
    class Document extends React.Component {
      render() {
        // ...
      }
    }
    
    export default withLinkAnalytics((props) => ({
      documentId: props.documentId
    }), Document);
    
    このように、Dockmentコンポーネントは依然として自分の関心すべき部分だけに関心を持ち、withLink Analyticsは多重化統計論理の能力を与えている.
    高次コンポーネントの存在は、Reactの生来の複合能力を完璧に示しており、Reactコミュニティでは、react-redux、style-components、react-intlなどが一般的に採用されています.特に、レcomposeクラスは高次のコンポーネントを利用して、大きく発揚して、「脳の穴が開く」ことができました.
    締め括りをつける
    Reactとその周辺コミュニティの台頭は、関数式プログラミングを一世を風靡させ、人気を集めています.その中でdecompsingとcompsingの思想については、とても勉強に値すると思います.同時に、開発設計に対する一つの提案は、あなたのコンポーネントをより小さく、より単一に分割することをためらわないでください.
    本文はDavid TangのTechniques for decomponentsを意訳しました.
    Happy Coding
    PS:著者Github倉庫、コードを通じて様々な形で交流することを歓迎します.