React Context 提供者太多

IT技术 reactjs react-context
2021-05-13 08:56:35

刚在这里做出react并试图围绕新的 Context API(我还没有研究过 Redux 等)。

似乎我可以做很多我需要做的事情,但我最终会得到很多提供者,所有提供者都需要一个标签来包装我的主应用程序。

我将有一个用于身份验证的提供者,一个用于主题,一个用于聊天消息(vis Pusher.com)等。此外,使用 React Router 是另一个包装器元素。

我是否将不得不以这个(以及更多)告终......

<BrowserRouter>
    <AuthProvider>
        <ThemeProvider>
            <ChatProvider>
                <App />
            </ChatProvider>
        </ThemeProvider>
    </AuthProvider>
</BrowserRouter>

或者,还有更好的方法?

4个回答

如果您想要一种无需任何第三方库即可组合 Providers 的解决方案,这里有一个带有 Typescript 注释的解决方案:

// Compose.tsx

interface Props {
    components: Array<React.JSXElementConstructor<React.PropsWithChildren<any>>>
    children: React.ReactNode
}

export default function Compose(props: Props) {
    const { components = [], children } = props

    return (
        <>
            {components.reduceRight((acc, Comp) => {
                return <Comp>{acc}</Comp>
            }, children)}
        </>
    )
}

用法:

<Compose components={[BrowserRouter, AuthProvider, ThemeProvider, ChatProvider]}>
    <App />
</Compose>

如果您不使用 Typescript,您当然可以删除注释。

for循环的解决方案

export const provider = (provider, props = {}) => [provider, props];

export const ProviderComposer = ({providers, children}) => {
    for (let i = providers.length - 1; i >= 0; --i) {
        const [Provider, props] = providers[i];
        children = <Provider {...props}>{children}</Provider>
    }
    return children;
}

用法:

<ProviderComposer
    providers={[
        provider(AuthProvider),
        provider(ThemeProvider),
        provider(MuiPickersUtilsProvider, {utils: DateFnsUtils}),
    ]}
>
    <App/>
</ProviderComposer>

使用@ rista404的答案- https://stackoverflow.com/a/58924810/4035
react-context-composer已过时。

感谢@AO17,为ping


免责声明:我从未使用过这个,只是研究过。

FormidableLabs(他们为许多OSS 项目做出了贡献)有一个名为react-context-composer 的项目

它似乎解决了你的问题。

React 提出了一个新的 Context API。API 鼓励组合。当您的组件将呈现多个上下文提供者和消费者时,此实用程序组件有助于保持您的代码干净。

几行代码即可解决您的问题。

import React from "react"
import _ from "lodash"

/**
 * Provided that a list of providers [P1, P2, P3, P4] is passed as props,
 * it renders
 *
 *    <P1>
        <P2>
          <P3>
            <P4>
              {children}
            </P4>
          </P3>
        </P2>
      </P1>
 *
 */

export default function ComposeProviders({ Providers, children }) {
  if (_.isEmpty(Providers)) return children

  return _.reverse(Providers)
    .reduce((acc, Provider) => {
      return <Provider>{acc}</Provider>
    }, children)
}