Ввод контекста реакции, чтобы избежать неопределенного значения по умолчанию

React Context API действительно полезен, когда дело доходит до обмена данными между отключенными компонентами без бурения опоры.

В последние несколько дней я работал над второстепенным проектом и дал Context API возможность поделиться своей аутентифицированной пользовательской информацией между компонентами маршрута. Следуя очень полезному шаблону, которым Кент С. Доддс на своем веб-сайте под заголовком Как эффективно использовать контекст React, я создал собственный hook для обработки логики потока аутентификации и поделился возвращенным значением с context, чтобы оно было доступно во всем приложении.

Примечание. Я не буду вдаваться в основы React Context API и React Hooks, поскольку это выходит за рамки статьи.

Я создал упрощенную версию шаблона, используемого в моем проекте, поскольку цель этой статьи - просто показать вам, как я использовал Typescript для правильного ввода шаблона, описанного выше. В этом примере мы хотим, чтобы приложение знало о статусе открытия / закрытия боковой панели.

Пользовательский крючок

Пользовательский хук позаботится об обработке состояния боковой панели и вернет текущее состояние и действие setState, используемое для запуска изменения состояния:

Контекстный API

Теперь мы хотим создать для нашего контекста состояние настраиваемого хука, сначала мы объявим наш контекст:

const SidebarContext = React.createContext<UseSidebar | undefined>(undefined);

Ввод нашего контекста - это настоящая боль, поскольку createContext ожидает, что мы предоставим значение по умолчанию, которое в некоторых случаях не имеет смысла предоставлять или о котором мы не знаем, для этого причина, по умолчанию мы будем использовать undefined. Основная проблема, вызванная этим подходом, заключается в том, что нам придется проверять наличие undefined каждый раз, когда мы будем пытаться использовать наш контекст. Простое решение - использовать ненулевое утверждение «!», которое позволит нам сообщить TypeScript, что во время выполнения параметр не будет иметь значение null или undefined:

const SidebarContext = React.createContext<UseSidebar>(undefined!);

это решение работает нормально, но не идеально, также мы все еще передаем значение нашему createContext, мы сохраним этот код на данный момент и поработаем над более надежным решением позже.

Теперь мы можем создать компонент Provider для нашего контекста:

interface Props {
  children: React.ReactNode;
}
const SidebarProvider = ({ children }: Props) => {
const [isOpen, setIsOpen] = useSidebar<boolean>(true);
return (
  <SidebarContext.Provider value={[isOpen, setIsOpen]}>
    {children}
  </SidebarContext.Provider>
  );
};

isOpen и setIsOpen теперь будут доступны и актуальны для дочерних элементов провайдера.

Теперь нам просто нужен настраиваемый обработчик, который позволит нашим компонентам использовать контекст, и, наконец, мы можем экспортировать его вместе с SidebarProvider:

const useSidebarContext = () => {
  return React.useContext(SidebarContext);
};
export { SidebarProvider, useSidebarContext };

Вот весь код:

Потребление контекста

Теперь нам нужно разместить Provider в нужном месте, чтобы все дочерние элементы Provider имели доступ к контексту:

Теперь наш контекст будет доступен для приложения и его дочерних компонентов. Например, мы можем использовать это так:

Вы можете посмотреть весь код в Code Sandbox

Удалите ненулевое утверждение и значение по умолчанию

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

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

В этой функции мы создаем контекст с универсальным типом и значением по умолчанию undefined, затем мы создаем другую функцию, чтобы проверить, определено ли значение общего контекста, если оно не определено, мы выдаем ошибку, по этой причине useGenericContext никогда не вернет неопределенное значение. Наконец, поскольку мы хотим, чтобы наш createGenericContext возвращал кортеж, мы используем «as const» после возвращаемого массива, делая количество элементов фиксированным и с определенным типом, выводимым TypeScript.

Использование функции createGenericContext

В нашей новой функции нам нужно отредактировать файл useSidebarContext вместо использования React.createContext функции, которую мы будем использовать общую функцию, которую мы создали, а затем использовать возвращенный кортеж внутри нашего код:

Вы можете посмотреть весь новый код в Code Sandbox.

Вот и все! Спасибо, если вы зашли так далеко, понимание вышеизложенных концепций дало мне хорошее понимание контекста и мира TS, надеюсь, вы сочли это полезным!