我如何避免React/JSX厄运金字塔?



我喜欢在我的React和React Native项目中使用上下文,这意味着每个项目有多个上下文提供程序。因此,我的应用程序的根目录通常是这样的:

<ContextA.Provider value={valueA}>
<ContextB.Provider value={valueB}>
<ContextC.Provider value={valueC}>
// ...and so on until rendering actual app content
</ContextC.Provider>
</ContextB.Provider>
</ContextA.Provider>

这会创建一个提供者的金字塔,看起来和感觉都是糟糕的风格/实践。

我可以把我的上下文值合并成一个大的提供者:

<BigContext.Provider value={ valueA, valueB, valueC }>
/// app content
</BigContext.Provider>

…但是有几个很好的理由想要保持上下文分开-主要是防止组件只对valueA感兴趣,从重新渲染当只有valueB改变,例如。

即使没有上下文,您仍然可以将来自不同包的提供程序堆叠到自己的金字塔中。下面是我的一个React Native应用程序的根目录,例如:

<DataContext.Provider value={data}>
<AppearanceProvider>
<SafeAreaProvider>
<NavigationContainer>
<Tab.Navigator>
// tab screens here
</Tab.Navigator>
</NavigationContainer>
</SafeAreaProvider>
</AppearanceProvider>
</DataContext.Provider>

是否有一种干净的方法来"崩溃"或以某种方式避免这些厄运金字塔?

"清理"对性能没有任何好处。也就是所谓的末日金字塔拥有多个关卡是完全可以的.

在实现下面的代码之前,请确保不要仅仅因为可以而在全局级别提供上下文。上下文提供程序必须包装在使用它的组件附近,这意味着不总是在根级别。

也就是说,这里有一个简单的高阶组件,它可以包装多个提供者来提供Reduxcompose风格的API。

/**
* Check if the object has a property matching the key
* NOTE: Works only for shallow objects.
* @param object
* @param key
* @returns {boolean|boolean}
*/
const hasProperty = (object, key) =>
object ? Object.hasOwnProperty.call(object, key) : false;
const hasProps = (arg) =>
hasProperty(arg, 'provider') && hasProperty(arg, 'props');
export const withContextProviders = (...providers) => (Component) => (props) =>
providers.reduceRight((acc, prov) => {
let Provider = prov;
if (hasProps(prov)) {
Provider = prov.context;
const providerProps = prov.props;
return <Provider {...providerProps}>{acc}</Provider>;
}
return <Provider>{acc}</Provider>;
}, <Component {...props} />);

用法:

const Component = () => {...}
export withContextProviders(ThemeProvider, I8nProvider)(Component)
// OR
export withContextProviders({provider: ThemeProvider, props: {darkMode: true}}, I8nProvider)(Component)
// OR
export withContextProviders(ThemeProvider, {provider: I8nProvider, props: {lang: 'en'}})(Component)
// OR
const providers = [{provider: ThemeProvider, props: {darkMode: true}}, {provider: I8nProvider, props: {lang: 'en'}}]
export withContextProviders(...providers)(Component)

注意:这不会产生单例,也就是说,如果两个组件用这个HoC包装,它们都将获得它们自己的上下文实例。对于这种情况,建议在根级别

用provider包装组件。

同样,拥有多个关卡是完全可以的.

世界末日金字塔>可以像这样折叠:

import { cloneElement } from "react";
function MyProviders({children}) {
return [
<ProviderOne />
<ProviderTwo />
<ProviderThree />
<ProviderFour />
<ProviderFive>{children}</ProviderFive>
].reduceRight((accumulator, currentValue) => cloneElement(currentValue, {}, accumulator))
}

最新更新