使用する 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);
これはtransclusion
Angular としても知られています。
children
Reactの特別な小道具であり、コンポーネントのタグ内にあるものが含まれます(ここに<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年のトレンドに拘束されないでください。