Context.Providerの数が多いとネストが深くなる問題について
公式ドキュメントのの例における以下の部分
// コンテクストの初期値を与える App コンポーネント
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
これは2つのコンテキストProviderでラップしているが、これが多くなるとネストが深くなってくのが嫌だなという問題。
// (コンテキスト名は適当)
return (
<ThemeContext.Provider value={theme}>
<UserGroupContext.Provider value={{}}>
<UserContext.Provider value={signedInUser}>
<PlacementContext.Provider value={{}}>
<HogeContext.Provider value={{}}>
<FugaContext.Provider value={{}}>
<PiyoContext.Provider value={{}}>
<Layout />
</PiyoContext.Provider>
</FugaContext.Provider>
</HogeContext.Provider>
</PlacementContext.Provider>
</UserContext.Provider>
</UserGroupContext.Provider>
</ThemeContext.Provider>
);
}
これが嫌かどうかは個人の感じ方もあるかもしれないが、以下に示す書き方の方がすっきりする。
h1. 解決
import React from 'react';
/**
* コンポーネントリストを入れ子にして連結したコンポーネントを返す
* @param components
* @returns {*|(function(...[*]): *)|(function(*): *)}
*/
const composeComponents = (...components) => {
if (components.length === 0) {
return (arg) => arg;
}
if (components.length === 1) {
return components[0];
}
return components.reduce((A, B) => (props) => <A><B {...props} /></A>);
};
const ComposedProvider = composeComponents(
(props) => <ThemeContext.Provider {...props} value={theme} />,
UserGroupContext.Provider,
(props) => <UserContext.Provider {...props} value={signedInUser} />,
HogeContext.Provider,
FugaContext.Provider,
PiyoContext.Provider,
);
/* (途中省略) */
return (
<ComposedProvider>
<Layout />
</ComposedProvider>
);
コンポーネントをreduceを使って連結する関数を用意しておいて、連結結果でラップするように書くとキレイだし、順番を入れ替えたりするのも楽。