使用する children
const Wrapper = ({children}) => (
<div>
<div>header</div>
<div>{children}</div>
<div>footer</div>
</div>
);
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = ({name}) => (
<Wrapper>
<App name={name}/>
</Wrapper>
);
render(<WrappedApp name="toto"/>,node);
これはtransclusionAngular としても知られています。
childrenReactの特別な小道具であり、コンポーネントのタグ内にあるものが含まれます(ここに<App name={name}/>があるWrapperため、children
childrenコンポーネントに固有のを必ずしも使用する必要はなく、必要に応じて通常の小道具を使用したり、小道具と子を組み合わせたりすることができます。
const AppLayout = ({header,footer,children}) => (
<div className="app">
<div className="header">{header}</div>
<div className="body">{children}</div>
<div className="footer">{footer}</div>
</div>
);
const appElement = (
<AppLayout
header={<div>header</div>}
footer={<div>footer</div>}
>
<div>body</div>
</AppLayout>
);
render(appElement,node);
これは多くのユースケースでシンプルで問題なく、ほとんどのコンシューマーアプリに推奨します。
小道具をレンダリングする
レンダー関数をコンポーネントに渡すことができます。このパターンは一般的にと呼ばれrender prop、childrenプロップはそのコールバックを提供するためによく使用されます。
このパターンは実際にはレイアウト用ではありません。ラッパーコンポーネントは、通常、いくつかの状態を保持および管理し、そのレンダリング関数に挿入するために使用されます。
カウンターの例:
const Counter = () => (
<State initial={0}>
{(val, set) => (
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
)}
</State>
);
あなたはさらに豪華になり、オブジェクトを提供することさえできます
<Promise promise={somePromise}>
{{
loading: () => <div>...</div>,
success: (data) => <div>{data.something}</div>,
error: (e) => <div>{e.message}</div>,
}}
</Promise>
必ずしも使用する必要はありませんchildren。これは好み/ APIの問題です。
<Promise
promise={somePromise}
renderLoading={() => <div>...</div>}
renderSuccess={(data) => <div>{data.something}</div>}
renderError={(e) => <div>{e.message}</div>}
/>
今日、多くのライブラリがレンダープロップ(Reactコンテキスト、React-motion、Apollo ...)を使用しています。これは、このAPIがHOCよりも簡単である傾向があるためです。react-powerplugはシンプルなrender-propコンポーネントのコレクションです。react-adoptは構成を行うのに役立ちます。
高次コンポーネント(HOC)。
const wrapHOC = (WrappedComponent) => {
class Wrapper extends React.PureComponent {
render() {
return (
<div>
<div>header</div>
<div><WrappedComponent {...this.props}/></div>
<div>footer</div>
</div>
);
}
}
return Wrapper;
}
const App = ({name}) => <div>Hello {name}</div>;
const WrappedApp = wrapHOC(App);
render(<WrappedApp name="toto"/>,node);
アン高次コンポーネント/ HOC一般的に部品を取り、新しいコンポーネントを返す関数です。
高次コンポーネントを使用すると、ラッパーにを使用してレンダリングを短絡させることができるため、childrenまたはを使用するよりもパフォーマンスが向上render propsしshouldComponentUpdateます。
ここではを使用していPureComponentます。アプリを再レンダリングするときに、WrappedApp名前プロップが時間とともに変化しない場合、ラッパーは「プロップ(実際には名前)は以前と同じであるため、レンダリングする必要がない」と言うことができます。children上記のベースのソリューションではPureComponent、ラッパーがであっても、親がレンダリングされるたびに子要素が再作成されるため、ラップされたコンポーネントが純粋であっても、ラッパーは常に再レンダリングされる可能性があります。これを軽減し、長期にわたって一定の要素を確保できるバベルプラグインがありchildrenます。
結論
高次コンポーネントを使用すると、パフォーマンスが向上します。それほど複雑ではありませんが、最初は不親切に見えます。
これを読んだ後、コードベース全体をHOCに移行しないでください。アプリのクリティカルパスでは、パフォーマンス上の理由からランタイムラッパーの代わりにHOCを使用することをお勧めします。特に、同じラッパーが何度も使用される場合は、HOCにすることを検討する価値があります。
Reduxは最初にランタイムラッパー<Connect>を使用しconnect(options)(Comp)、パフォーマンス上の理由からHOCに後で切り替えました(デフォルトでは、ラッパーは純粋で使用されていますshouldComponentUpdate)。これは、私がこの回答で強調したかったことの完璧な例です。
コンポーネントにrender-prop APIが含まれている場合、通常、その上にHOCを作成するのは簡単です。そのため、ライブラリ作成者は、最初にrender prop APIを記述し、最終的にHOCバージョンを提供する必要があります。これは、Apolloが<Query>render-propコンポーネントとgraphqlそれを使用するHOCで行うことです。
個人的には両方を使用していますが、疑わしい場合は次の理由でHOCを使用します。
compose(hoc1,hoc2)(Comp)小道具をレンダリングするよりも、それらを構成するほうが慣用的です()
- それは私に良いパフォーマンスを与えることができます
- 私はこのスタイルのプログラミングに精通しています
私はお気に入りのツールのHOCバージョンを使用/作成することをためらっていません。
- Reactの
Context.Consumerコンプ
- 記載されていない
Subscribe
- レンダープロップの
graphql代わりにアポロのHOCを使用Query
私の意見では、レンダープロップによってコードが読みやすくなる場合がありますが、場合によってはコードが読みにくくなることがあります...自分の制約に従って、最も実用的なソリューションを使用しようとします。パフォーマンスよりも読みやすさが重要な場合もあれば、そうでない場合もあります。賢明に選択し、すべてをレンダープロップに変換する2018年のトレンドに拘束されないでください。