Reactのデザインパターン

Reactエコシステムに存在する過程で出現し進化したデザインパターンは、コードの可読性とクリーンさを向上させ、コンポーネントの再利用を促進します。



この資料の著者は、彼が約3年前にReactで働き始めたと言っています。 当時、確立された慣行はなく、開発の質を向上させることができるものを調査し、その後を追跡しました。



Reactコミュニティが、現在人気のあるいくつかのアイデアを思い付くまでに約2年かかりました。 ここでは、 React.createClass



からReact.createClass



クラスへの移行、および純粋な機能コンポーネントへの移行、ミックスインの拒否、APIの簡素化に注目できます 。 現在、React開発者の数が絶えず増えているという事実、このプロジェクトの開発に真剣な努力が注がれているという事実を考えると、いくつかの興味深いデザインパターンの進化を観察できます。 これらのテンプレートは、この資料専用です。



条件付きレンダリング



条件付きレンダリングから始めましょう。 私は多くのプロジェクトで次のシナリオを見てきました。 重要なのは、ReactとJSXを使用している間、開発者はHTMLとJavaScriptの観点からこれらのテクノロジーを検討する傾向があることです。 その結果、条件付きロジックが返されたコードから分離されるのは当然です。



 const condition = true; const App = () => { const innerContent = condition ? (   <div>     <h2><font color="#3AC1EF">Show me</font></h2>     <p>Description</p>   </div> ) : null; return (   <div>     <h1>This is always visible</h1>     { innerContent }   </div> ); };
      
      





同様の構成では、各render()



関数の先頭に条件付き三項演算子があり、すぐに手に負えなくなる傾向があります。 この要素またはその要素が表示されるかどうかを理解するには、常に機能コードを調べる必要があります。



または、言語の機能を使用して、次のテンプレートを試すことができます。



 const condition = true; const App = () => ( <div>   <h1>This is always visible</h1>   {     condition && (       <div>         <h2><font color="#3AC1EF">Show me</font></h2>         <p>Description</p>       </div>     )   } </div> );
      
      





condition



false



場合、システムは&&



演算子の第2オペランドに到達しません。 true



場合、2番目のオペランド、つまりレンダリングしたいJSXコードが返されます。



これにより、宣言的なアプローチを使用して、ユーザーインターフェイスロジックとインターフェイス要素の説明を混在させることができます。 同時に、JSXはコードの不可欠な部分であるかのように認識される必要があります。 最終的に、これは単なるJavaScriptです。



プロパティをコンポーネントツリーに渡す



次の設計パターンでは、プロパティをコンポーネントツリーに渡します(propsを渡します)。 アプリケーションが成長して開発されると、他のコンポーネントのコンテナとして機能する小さなコンポーネントで構成されていることがわかります。 その結果、これらのコンポーネントの子孫を対象とし、親コンポーネントによって使用されないコンポーネントを介して、大量のプロパティを転送する必要があります。 このような状況では、プロパティの破壊、拡張演算子の使用に頼ることができます。



 const Details = ( { name, language } ) => ( <div>   <p>{ name } works with { language }</p> </div> ); const Layout = ( { title, ...props } ) => ( <div>   <h1>{ title }</h1>   <Details { ...props } /> </div> ); const App = () => ( <Layout   title="I'm here to stay"   language="JavaScript"   name="Alex" /> );
      
      





この例では、 Details



必要なプロパティを変更し、複数のコンポーネントにこれらのプロパティへの参照がないことを確認できます。



プロパティの再構築



破壊の小道具パターンについて話しましょう。 時間が経つにつれて、アプリケーションが変わり、コンポーネントでも同じことが起こります。 数年前に記述されたコンポーネントは状態を使用できますが、現在の状態では、ステートレスコンポーネントに変換できます。 多くの場合、反対の状況を見ることができます。



プロパティの再構築の可能性を使用して、長期的にはプロジェクトでの作業を促進するために使用する便利な手法を使用できます。 両方のタイプのコンポーネントのプロパティが低下する可能性があります。



 const Details = ( { name, language } ) => ( <div>   <p>{ name } works with { language }</p> </div> ); class Details extends React.Component { render() {   const { name, language } = this.props;   return (     <div>       <p>{ name } works with { language }</p>     </div>   ) } }
      
      





行2〜4および11〜13(つまり、 <div>



タグ)は同一であることに注意してください。 このテンプレートは、コンポーネントの変換を容易にします。 さらに、このアプローチは、コンポーネント内でのthis



の使用を制限します。



プロバイダーテンプレート



設計パターン「プロバイダー」は、比較的最近登場したReactの機能を指します。 上記では、特定のコンポーネントの子孫にプロパティを送信する必要がある例を分析しました。 この操作は、コンポーネント受信者のプロパティの数が増えるため複雑になります。 たとえば、プロパティを15のコンポーネントに転送する必要がある場合はどうなりますか? この状況では、 React Context APIを使用すると便利です。 これは、このReact機能がどのような状況でも役立つと言うことではありませんが、必要なときに便利です。



ここで、設計テンプレート「プロバイダ」の実装を含むContext



新しいAPIの出現が比較的最近発表されたと言わなければなりません。 このテンプレートは、React ReduxやApolloなどを使用している人なら誰でも知っているはずです。 既存の機能を使用して新しいAPIを処理するには、 このコードを試してください。



このモデルでは、最上位コンポーネントはプロバイダーと呼ばれます。 コンテキストにいくつかの値を書き込みます。 コンシューマと呼ばれる子コンポーネントは、コンテキストからこれらの値を取得します。



コンテキストを操作するための構文は少し奇妙に見えますが、Reactの次のバージョンでは、この特定のテンプレートを実装することが期待されています。



高次コンポーネント



高次コンポーネント (HOC)テンプレートについての会話は、コードの再利用のアイデアから始める価値があります。 古いファクトリー関数React.createElement()



の放棄とともに、ReactチームはReact.createElement()



サポートも拒否しました。 それらは、ある程度、通常のオブジェクトの構成によるコンポーネント構成の標準的なアプローチでした。 高次のコンポーネントは、多数のコンポーネントの再利用のニーズを満たすように設計されています。



高次コンポーネントは、入力コンポーネントを取得し、そのコンポーネントの拡張バージョンまたは変更バージョンを返す関数です。 「高次コンポーネント」と呼ばれるものには多くの名前がありますが、デコレーターとして使用することを好みます。



Reduxを使用する場合、 connect



関数で高次コンポーネントを認識します。これは、コンポーネントを受け入れることにより、いくつかのプロパティを追加します。



既存のコンポーネントにプロパティを追加できる単純な高次コンポーネントを実装します。



 const withProps = ( newProps ) => ( WrappedComponent ) => { const ModifiedComponent = ( ownProps ) => ( //      <WrappedComponent { ...ownProps } { ...newProps } /> //   +   ); return ModifiedComponent; }; const Details = ( { name, title, language } ) => ( <div>   <h1>{ title }</h1>   <p>{ name } works with { language }</p> </div> ); const newProps = { name: "Alex" }; //      const ModifiedDetails = withProps( newProps )( Details ); //        const App = () => ( <ModifiedDetails   title="I'm here to stay"   language="JavaScript" /> );
      
      





関数型プログラミングが好きなら、高次のコンポーネントで作業するのも好きでしょう。 ここで、 withContext



ことができます。これは、 withProps



withContext



lifecycle



などの高次コンポーネントを開発者が自由に使用できる優れたパッケージです。



機能の再利用の例をご覧ください。



 function withAuthentication(WrappedComponent) { const ModifiedComponent = (props) => {   if (!props.isAuthenticated) {     return <Redirect to="/login" />;   }   return (<WrappedComponent { ...props } />); }; const mapStateToProps = (state) => ({   isAuthenticated: state.session.isAuthenticated }); return connect(mapStateToProps)(ModifiedComponent); }
      
      





withAuthentication



は、 withAuthentication



好きな目を意図していないルートにデータを表示する必要がある場合に使用できることに注意してください。 このデータは、ログインしているユーザーのみが利用できます。



ここに横断的な機能の例があり、一箇所に実装され、アプリケーション全体での再利用に適しています。



ただし、高次コンポーネントにも欠点があります。 そのような各コンポーネントは、DOM / vDOMに追加のReactコンポーネントを作成します。 これは、アプリケーションが成長するにつれて、潜在的なパフォーマンスの問題につながる可能性があります。



この記事では、高次コンポーネントに関する追加の問題について説明します 。 ここでは、特に、高次のコンポーネントをテンプレートで置き換えることが提案されていますが、これを次に検討します。



レンダリングの小道具テンプレート



「レンダープロップ」テンプレート、または「子孫として機能」テンプレートとも呼ばれるテンプレートを使用すると、高次コンポーネントで達成可能なものと同じことが実現できます。 これらのテンプレートは交換可能です。 それらを比較すると、私はそれらのいずれかに絶対的な優先権を与えることはできません。 両方のテンプレートを使用して、コードを簡潔にし、再利用性を向上させます。



簡単に言うと、レンダープロップテンプレートを使用するという考え方は、レンダリング関数の制御を別のコンポーネントに転送し、関数であるプロパティを通じて制御を返すことです。 同じ効果を得るために動的プロパティを使用することを好む人もいれば、単にthis.props.children



を使用する人もいます。



おそらく、これをすべて例で説明するのが最善でしょう。



 class ScrollPosition extends React.Component { constructor( ) {   super( );   this.state = { position: 0 };   this.updatePosition = this.updatePosition.bind(this); } componentDidMount( ) {   window.addEventListener( "scroll", this.updatePosition ); } updatePosition( ) {   this.setState( { position: window.pageYOffset } ) } render( ) {   return this.props.children( this.state.position ) } } const App = () => ( <div>   <ScrollPosition>     { ( position ) => (       <div>         <h1>Hello World</h1>         <p>You are at { position }</p>       </div>     ) }   </ScrollPosition> </div> );
      
      





ここでは、プロパティとして、 children



使用されます。 <ScrollPosition>



コンポーネントに、 position



をパラメーターとして取る関数を送信します。



render propsテンプレートは、コンポーネント内での再利用に適したロジックが必要な状況で使用できますが、このコンポーネントは高次のコンポーネントにラップされる予定はありません。 render propsテンプレートの使用例は、 React-Motionライブラリにあります。 render propsテンプレートでの非同期ストリームの使用を示すFetch



コンポーネント作成例です



最後に、同じコンポーネントで複数の子関数を使用できることに注意してください。 render propsテンプレートは、開発者に機能の合成と再利用の無限の可能性を与えます。



まとめ



この記事では、いくつかのReactテンプレートを検討しましたが、そのうちのいくつかは長い間存在していましたが、いくつかは比較的最近登場しました。 テンプレートを使用することで時間を節約し、コードを改善するという典型的な問題を解決する信頼できる方法を開発者に提供するため、テンプレートに精通していると便利です。



親愛なる読者! Reactに基づいてプロジェクトで使用するテンプレートは何ですか?






All Articles