Слишком много поставщиков контекста React

Новичок, чтобы отреагировать здесь и попытаться обернуть голову вокруг нового API контекста (я еще не изучал Redux и т. Д.).

Кажется, я могу делать многое из того, что мне нужно, но в конечном итоге у меня будет много-много провайдеров, и всем понадобится тег для обертывания моего основного приложения.

У меня будет провайдер для Auth, один для тематики, один для сообщений чата (vis Pusher.com) и т. Д. Также использование React Router - это еще один элемент оболочки.

Придется ли мне закончить с этим (и многим другим) ....

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

Или есть способ лучше?


person jonhobbs    schedule 24.07.2018    source источник
comment
Это то, что решает Redux.   -  person coreyward    schedule 24.07.2018
comment
Хм, я боялся, что кто-то может это сказать, но я пытаюсь прислушаться к совету тех, кто сказал попробовать изучить состояние в React, прежде чем прибегать к Redux. Немного взглянув на Redux и MoX, я думаю, что с большей вероятностью попробую MobX.   -  person jonhobbs    schedule 24.07.2018
comment
Вышеупомянутое - хороший пример использования Redux; отступление происходит потому, что местный штат часто бывает прекрасен. Вы не хотите идти на ненужные компромиссы. См. эту отличную запись автора Redux Дэна Абрамова «Вы не можете Нужен Redux ».   -  person coreyward    schedule 24.07.2018
comment
Многие люди говорят, что перехватчики API Context или React отправят Redux в корзину, но Redux по-прежнему остается Redux, и все 3 метода должны использоваться для разных систем. В случае, если у вас есть глобальное хранилище, вам нужно повлиять на весь ваш веб-сайт: Redux - это ключ, и он будет еще более мощным, чем API-контекст (за счет того, что компонент не будет ездить по всей DOM (например, для авторизации или провайдера чата) . Тема может быть обновлена ​​в каскадном режиме, как CSS, поэтому контекст API - лучший выбор.   -  person Arthur    schedule 20.02.2020
comment
Действительно ли этот шаблон создает какие-либо проблемы, кроме того факта, что список визуально длинный, что также делает просматриваемую страницу широкой?   -  person shawn98ag    schedule 08.05.2020
comment
Мне также нравится учитывать, нужен ли всему моему приложению доступ ко всей информации из любого контекста. Браузеры, темы, аутентификация и т. Д., Очевидно, будут, но я иногда обнаруживаю, что некоторые из них можно уменьшить, поместив контексты как можно глубже в поддереве.   -  person reustin    schedule 30.04.2021


Ответы (6)


Если вам нужно решение для создания поставщиков без каких-либо сторонних библиотек, вот решение с аннотациями 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.

person rista404    schedule 19.11.2019
comment
Добавьте свойства, когда это необходимо поставщику: const {components = [], children, ... rest} = props. ...... возврат ‹Comp {... rest}› {acc} ‹/Comp› - person Ken Lee; 13.07.2020

Используйте ответ @ rista404 - https://stackoverflow.com/a/58924810/4035
поскольку react-context-composer устарел.

Спасибо @ AO17 за пинг.


Отказ от ответственности: Я никогда не использовал это, просто исследовал.

FormidableLabs (они участвуют во многих проектах OSS) имеет проект под названием react-context-composer

Кажется, это решило вашу проблему.

React предлагает новый контекстный API. API поощряет сочинение. Этот служебный компонент помогает содержать ваш код в чистоте, когда ваш компонент будет отображать несколько поставщиков и потребителей контекста.

person dance2die    schedule 24.07.2018
comment
Это выглядит очень многообещающе. Я не совсем понимаю их примерный код (например, WTH - это Context ‹Theme›?), Но я собираюсь попробовать и отмечу как правильный, если он работает. Большое спасибо. - person jonhobbs; 25.07.2018
comment
@jonhobbs В примере используется flow в соответствии с этим примером, github.com/jamiebuilds/create-react -context # example - person dance2die; 25.07.2018
comment
пакет заархивирован, воспользуйтесь решением от @ rista404 - person AO19; 20.02.2020
comment
@ AO17 Большое спасибо за предупреждение ~ Обновлен ответ. - person dance2die; 20.02.2020

Решение с 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>
person Milan Majer    schedule 27.10.2020

Несколько строк кода решат вашу проблему.

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)
}
person Hellon Canella Machado    schedule 29.10.2019

Одно из простых решений - использовать что-то похожее на функцию compose в https://github.com/reduxjs/redux/blob/master/src/compose.js и объедините всех поставщиков вместе.

provider.js

const Providers = compose(
    AuthProvider,
    ThemeProvider,
    ChatProvider
);

также я не использовал это решение, но с новой функцией перехватчиков React вместо рендеринга ваших контекстов вы можете использовать перехватчик реакции для доступа к нему в определении функции.

person Haswin    schedule 20.03.2019
comment
Я пробовал это, но продолжал получать TypeError: Cannot call a class as a function - person Barryman9000; 15.04.2019
comment
Страница не найдена при попытке доступа по ссылке - person Purkhalo Alex; 06.03.2020
comment
Теперь это файл TypeScript (compose.ts) github.com/reduxjs/ redux / blob / master / src / compose.ts - person Luis Rizo; 24.08.2020

перекомпоновка js-помощника по вложению, если вам нужно добавить внешние реквизиты для использования элемента провайдера withprops hoc

person Azat Temirbek uulu    schedule 12.06.2021
comment
Добро пожаловать в StackOverflow! Когда вы отвечаете на вопрос, не забудьте дать четкие и задокументированные ответы. Добавьте фрагменты кода, чтобы объяснить, что вы имеете в виду, и / или предоставьте ценные ссылки, дающие дополнительные пояснения к опубликованному вами решению! - person AndreaCostanzo1; 14.06.2021