Как объединить пользовательских провайдеров хуков, но сохранить их случаи использования отдельно - PullRequest
0 голосов
/ 09 апреля 2020

Я создал несколько пользовательских хуков, и мне интересно, смогу ли я объединить их контекст Providers.

У меня есть что-то вроде этого:

HookA

const ContextA = createContext({ value })

export const ProviderA = ({ children }) => {
  return (
    <ContextA.Provider value={{ myVal: 'A' }}>
      {children}
    </ContextA.Provider>
  )
}

export const useA = () => {
  const { myVal } = useContext(ContextA)
  return { myVal }
}

HookB

const ContextB = createContext({ value })

export const ProviderB = ({ children }) => {
  return (
    <ContextB.Provider value={{ myVal: 'B' }}>
      {children}
    </ContextB.Provider>
  )
}

export const useB = () => {
  const { myVal } = useContext(ContextB)
  return { myVal }
}

В настоящее время, чтобы использовать эти компоненты в компонентах, мне нужно обернуть приложение в провайдере следующим образом:

ReactDOM.render(
  <ProviderA>
    <ProviderB>
      <App />
    </ProviderB>
  </ProviderA>,
  document.getElementById('root')
)

Это возможно ли мне объединить их каким-то образом, например, создать CustomHooksProvider, который действует как поставщик для обеих ловушек, но продолжает позволять мне useA и useB, как я делал?

Что-то вроде этого:

ReactDOM.render(
  <CustomHooksProvider>
    <App />
  </CustomHooksProvider>,
  document.getElementById('root')
)

Как должен выглядеть мой CustomHooksProvider компонент?

1 Ответ

2 голосов
/ 09 апреля 2020

Создайте CustomHooksProvider компонент, который принимает children и отображает обоих провайдеров:

const CustomHooksProvider = ({ children }) => (
  <ProviderA>
    <ProviderB>
      {children}
    </ProviderB>
  </ProviderA>,
);

Более универсальный c подход - это функция, которая принимает список компонентов-оберток и генерирует новый компонент, который принимает дочерние элементы и отображает дочерние элементы внутри оболочек:

const wrapWith = (...wrappers) => ({ children }) => 
  wrappers.reduceRight((rendered, Component) => (
    <Component>
      {rendered}
    </Component>
  ), children);

А затем вы можете сгенерировать CustomHooksProvider, вызвав функцию wrapWith у своих провайдеров:

const CustomHooksProvider = wrapWith(ProviderA, ProviderB);

Демо:

const { createContext, useContext } = React;

const wrapWith = (...wrappers) => ({ children }) => 
  wrappers.reduceRight((rendered, Component) => (
    <Component>
    {rendered}
    </Component>
  ), children);

const ContextA = createContext({ value: '' })

const ProviderA = ({ children }) => {
  return (
    <ContextA.Provider value={{ myVal: 'A' }}>
      {children}
    </ContextA.Provider>
  )
}

const useA = () => {
  const { myVal } = useContext(ContextA)
  return { myVal }
}

const ContextB = createContext({ value: '' })

const ProviderB = ({ children }) => {
  return (
    <ContextB.Provider value={{ myVal: 'B' }}>
      {children}
    </ContextB.Provider>
  )
}

const useB = () => {
  const { myVal } = useContext(ContextB)
  return { myVal }
}

// generate the combined provider
const CustomHooksProvider = wrapWith(ProviderA, ProviderB);

const App = () => {
  const { myVal: a } = useA();
  const { myVal: b } = useB();
  
  return (
    <div>
      {a}
      {b}
    </div>
  );
};

ReactDOM.render(
  <CustomHooksProvider>
    <App />
  </CustomHooksProvider>,
  root
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...