レンダー外でレンダープロップテンプレートを使用する

Reactは、 render props



テンプレート )( 詳細 )を使用する新しいAPI( コンテキストAPI )を導入します。 セミナー、会議、Twitterでは、イベントハンドラーやライフサイクルフックなど、レンダー外でrender props



を使用render props



ことについて多くの質問があることがわかります。







画像







1年半前、React Router v4で作業していたとき、「ディープアップデート」の問題を一度だけ解決する方法に特に興味がありました。 Reactが新しいコンテキストAPIで導入したものと概念的に同一のAPIを使用して、 react-context-emission



(後のreact-broadcast



)と呼ばれるライブラリを作成しました。







 // React context emission API const { LocationEmitter, LocationSubscriber } = createContextEmission('location') <LocationEmitter location={value}/> <LocationSubscriber>{({ location }) => (...)}</LocationSubscriber> //  React Context API const { Provider, Consumer } = React.createContext() <Provider value={location}/> <Consumer>{value => (...)}</Consumer>
      
      





このテンプレートを使用した後、コンテキストを介して変数の値をコンポーネントにバインドしてプロパティを描画するのが本当に好きでしたが( レンダリングプロパティ)、レンダリング以外のコンテキスト値にアクセスするために最善を尽くしました。 私の実装では、 this.context



からそれらを取得することに慣れています。 これが、React Routerで現在の(非推奨?) contextTypes



APIを使用することに戻った理由の1つです。







この問題を解決することはそれほど難しくありません。 これを理解するにはしばらく時間がかかりました。 ただし、解決策を見るとすぐに、それは明らかなように見えます。 自分で見てください!







イベントハンドラーの値へのアクセス



必要なのは...値をハンドラーに渡すだけです:







 class Something extends React.Component { handleClick = (event, stuff) => { console.log(stuff); }; render() { return ( <SomeContext.Consumer> {stuff => ( <div> <h1>Cool! {stuff}</h1> <button onClick={event => this.handleClick(event, stuff)}> Click me </button> </div> )} </SomeContext.Consumer> ); } }
      
      





ライフサイクルフックの値にアクセスする



lifecycle hooks



以前のテンプレートは機能しません。 フックではなく、Reactを呼び出します。 私が使用した3つのテンプレートを提供し、どれが一番好きかを選択します(3番目が私のお気に入りです!)。







ラップ



コンテキストを使用するコンテナと、コンテキストをプロパティとして受け入れるコンテナの2つのコンポーネントを作成することで、データにアクセスできます。







 //   (,   ) const SomethingContainer = () => ( <SomeContext.Consumer> {stuff => <Something stuff={stuff} />} </SomeContext.Consumer> ); // ,  stuff  prop! Context      class Something extends React.Component { componentDidMount() { console.log(this.props.stuff); } render() { return ( <div> <h1>Cool! {this.props.stuff}</h1> </div> ); } }
      
      





高次コンポーネント(HOCコンポーネント)を作成する



一部のコンポーネントを他のコンポーネントで装飾するために既に使用されている場合があります(たとえば、HOC- High Order Componentを使用 )。 render prop



コンポーネントをより高次のコンポーネントにすばやく変えることができます。 コードを大幅にシャッフルし、それを実装するための多くの概念を必要とするため、私はこの方法があまり好きではありません。







 // HOC const withStuff = Comp => props => ( <SomeContext.Consumer> {stuff => <Comp stuff={stuff} />} </SomeContext.Consumer> ); //   class SomethingImpl extends React.Component { componentDidMount() { console.log(this.props.stuff); } render() { return ( <div> <h1>Cool! {this.props.stuff}</h1> </div> ); } } // the actual decoration const Something = withStuff(SomethingImpl)
      
      





コンポーネントコンポーネント:私の新しい愛。



関数をプロパティとして単純に取得し、componentDidUpdateの関数を呼び出すコンポーネントを作成したら、 すでにrender



というプロパティを作成しましたが、 didUpdate



というプロパティがもう1つdidUpdate



ます。 コンポーネントクラスの各メソッドをコンポーネントプロパティに変換できることに気付きました。これが@反応/コンポーネントの由来です。







コードをシャッフルすることなく、ライフサイクルフックでrender props



を作成render props



と非常に便利です。







 import Component from '@reactions/component'; const Something = () => ( <SomeContext.Consumer> {stuff => ( <Component didMount={() => console.log(stuff)}> <h1>Cool! {stuff}</h1> </Component> )} </SomeContext.Consumer> );
      
      





通常、プロパティはcomponentDidUpdate



で比較できますが、これも非常にうまく機能します。







 const Something = () => ( <SomeContext.Consumer> {stuff => ( <Component stuff={stuff} didUpdate={({prevProps, props}) => { console.log(prevProps.stuff === props.stuff); }} > <h1>Cool! {stuff}</h1> </Component> )} </SomeContext.Consumer> );
      
      





これは私のお気に入りの方法です。 コードは新しい概念を持たず、構造全体がコンポーネントごとに編成されているため、不整合なくコードを変更および移動できます。 ライフサイクルメソッドが不要になった場合、抽象化を解く必要はなく、 <Component/>



削除するだけです。







これで、必要なものはすべて揃いました。 すべてが明らかで、一度見るだけで済みますが、それ以前はすべてが複雑に見えました。








All Articles