Как создать общий поставщик контекста в React?

Я использую контекст реакции для обмена данными между компонентами.

Например, я мог бы создать пользовательский контекст:

const useFirebaseUser = () => {
  const [user, setUser] = useState({} as User);

  useEffect(() => {
    return firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        const { displayName, photoURL, uid } = user;
        setUser({
          displayName,
          photoURL,
          uid,
          isAuthenticated: true,
        } as User);
      } else {
        setUser({} as User);
      }
    });
  }, []);

  return user;
};

export const FirebaseUserContext = createContext({} as User);

export const GlobalFirebaseUserProvider = ({ children }: { children: ReactNode }) => (
  <FirebaseUserContext.Provider value={useFirebaseUser()}>{children}</FirebaseUserContext.Provider>
);

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


const useTodos = () => {
  const [todos, setTodos] = useState(['']);

  // ..

  return { todos, setTodos };
};

export const TodosContext = createContext(
  {} as { todos: string[]; setTodos: React.Dispatch<React.SetStateAction<string[]>> }
);

export const TodosContextProvider = ({ children }: { children: ReactNode }) => (
  <TodosContext.Provider value={useTodos()}>{children}</TodosContext.Provider>
);

По этому поводу я хочу абстрагироваться от ценностной части. Я пытаюсь создать универсального поставщика:

import React, { createContext, ReactNode } from 'react';

export const CreateGenericContext = <T extends {}>(value: T) => {
  const GenericContext = createContext({} as T);

  const GenericContextProvider = ({ children }: { children: ReactNode }) => (
    <GenericContext.Provider value={value}>{children}</GenericContext.Provider>
  );

  return { GenericContext, GenericContextProvider };
};

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

export const {
  GenericContext: UserContext,
  GenericContextProvider: UserContextProvier,
} = CreateGenericContext(useUser());

Однако сообщение об ошибке React throw: Ошибка: недопустимый вызов ловушки. Хуки могут быть вызваны только внутри тела функционального компонента. Это могло произойти по одной из следующих причин:

  1. У вас могут быть несовместимые версии React и средства визуализации (например, React DOM)
  2. Возможно, вы нарушаете правила крючков
  3. У вас может быть несколько копий React в одном приложении.

Означает ли это, что невозможно создать общий поставщик контекста для React? Я искал в Интернете, и учебник, похоже, показывает, что для контекста не используются крючки. Однако в случае использования перехватчиков реакции, как создать общий поставщик контекста в реакции?


person Jiahua Zhang    schedule 27.07.2020    source источник


Ответы (1)


Отложите настраиваемый перехватчик, перехватчик может быть вызван / вызван только внутри функционального компонента.

import React, { createContext, ReactNode } from 'react';

export const createGenericContext = <T extends {}>(hook: () => T) => {
  const GenericContext = createContext({} as T);

  const GenericContextProvider = ({ children }: { children: ReactNode }) => (
    <GenericContext.Provider value={hook()}>{children}</GenericContext.Provider>
  );

  return { GenericContext, GenericContextProvider };
};

person Jiahua Zhang    schedule 29.07.2020