Компонент, который добавляет своего собственного поставщика

#reactjs

Вопрос:

Мне поручено поддерживать несколько комплектов компонентов, применяя при этом единую систему проектирования. Чтобы помочь мне в этом, я реализовал a ThemeControllerProvider , который предоставляет общий объект темы в Context моих реальных поставщиках ThemeProviderA тем и ThemeProviderB .

Это означает, что приложение пользователя будет настроено примерно так.

 <ThemeControllerProvider mode="dark">
  <ThemeProviderA>
    <ThemeProviderB>
      <App/>
    </ThemeProviderB>
  </ThemeProviderA>
</ThemeControllerProvider>
 

Это работает нормально, но я хотел бы улучшить опыт разработчиков. Я хочу, чтобы разработчики не беспокоились о контроллере.

 <ThemeProviderA>
  <ThemeProviderB>
    <App/>
  </ThemeProviderB>
</ThemeProviderA>
 

Или когда они используют только один комплект компонентов…

 <ThemeProviderA>
  <App/>
</ThemeProviderA>
 

В моем ThemeControllerProvider есть редуктор Context , и мне удалось, чтобы каждый поставщик тем определял, присутствует ли контроллер или нет, проверяя, является ли редуктор нулевым или нет, но я не понял, что делать с этой информацией. Нижестоящим компонентам требуется controller.state.theme поддержка, но она не существует, когда comp инициализируется без уже существующего поставщика.

 // ThemeProviderA.jsx

const controller = useThemeController()

if (controller === null) {
  return (
    <ThemeControllerProvider>
      <ThemeProviderA theme={???}>
        {children}
      </ThemeProviderA>
    <ThemeControllerProvider>
  )
} else {
  return (
    <ThemeProviderA theme={controller.state.theme}>
      {children}
    </ThemeProviderA>
  )
}
 

Есть ли шаблон, который я могу реализовать, в котором поставщики тем могут автоматически обнаруживать отсутствие a ThemeControllerProvider и автоматически вводить его? А также, если поставщики тем вложены, мне нужен только поставщик высшего порядка для внедрения контроллера.

Ответ №1:

ладно, это очень интересная проблема.

Предположим, что вы ThemeControllerProvider также являетесь поставщиком контекста. Я могу сначала обдумать эту идею,

   const a = useContext(Context)
 

a Это не вызвало бы ошибок без зарегистрированного поставщика в качестве родителя. почему?

   Context = React.createContext(defaultContextValue)
 

Если поставщик не зарегистрирован, значение a будет defaultContextValue равно значению . В вашем случае мы можем установить значение по умолчанию пустым theme или каким-либо другим.

   const defaultContextValue = { theme: ... }
 

реализация

Конечно, я предполагаю, что ваш контроллер-это контекст.

 const ThemeControllerContext = React.createContext({ theme: null })
 

Остальная часть вашего кода все равно должна работать с этим изменением.

 if (controller === null) {
  return (
    <ThemeControllerContext.Provider value={theme}>
      <ThemeProviderA theme={???}>
        {children}
      </ThemeProviderA>
    <ThemeControllerContext>
  )
} else {
  return (
    <ThemeProviderA theme={controller.state.theme}>
      {children}
    </ThemeProviderA>
  )
}
 

прочитайте материал

https://javascript.plainenglish.io/react-context-is-a-global-variable-b4b049812028

Вы можете найти свой случай, отмеченный случаем D, в приведенной выше статье.