DevGang
Авторизоваться

React + Firebase: простой провайдер аутентификации на основе контекста 

В этом посте демонстрируется быстрый и простой способ сделать пользователя, прошедшего проверку подлинности Firebase, доступным во всем веб-приложении React.

Мы используем здесь простой React с Typescript и не задействуем дополнительную библиотеку управления состоянием, такую ​​как Redux.

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

import firebase from "firebase/app";

firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    console.log("authenticated", user);
  } else {
    console.log("signed out");
  }
});

Таким образом, мы могли бы довольно просто реализовать компонент React, который заинтересован в аутентифицированном пользователе:

import * as React from "react";
import firebase from "firebase/app";

function CurrentUser() {
  const [user, setUser] = React.useState<firebase.User | null>(null);

  React.useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged(setUser);
    return unsubscribe;
  }, []);

  return <div>{user?.displayName || "unauthenticated"}</div>;
}

Наш компонент React облегчает React.useEffect для регистрации обратного вызова Firebase onAuthStateChanged один раз после его установки. Эффект возвращает обратный вызов отказа от подписки onAuthStateChanged, гарантируя, что мы не запустимся при каких-либо утечках памяти.

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

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

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

Один из способов решить эту проблему - предоставить состояние аутентификации глобально, используя контекст React и сопутствующий хук. Начнем сначала с контекста:

// FirebaseAuthContext.tsx
import * as React from "react";
import firebase from "firebase/app";

type User = firebase.User | null;
type ContextState = { user: User };

const FirebaseAuthContext =
  React.createContext<ContextState | undefined>(undefined);

const FirebaseAuthProvider: React.FC = ({ children }) => {
  const [user, setUser] = React.useState<User>(null);
  const value = { user };

  React.useEffect(() => {
    const unsubscribe = firebase.auth().onAuthStateChanged(setUser);
    return unsubscribe;
  }, []);

  return (
    <FirebaseAuthContext.Provider value={value}>
      {children}
    </FirebaseAuthContext.Provider>
  );
};

export { FirebaseAuthProvider };

Здесь следует отметить несколько моментов:

  1. User - это псевдоним типа для аутентифицированного пользователя Firebase, возвращаемый onAuthStateChanged. Обратный вызов вызывается null, если ни один пользователь не аутентифицирован.
  2. ContextState -  это псевдоним типа для значения, предоставляемого нашим контекстом FirebaseAuthContext.
  3. Мы не выставляем FirebaseAuthContext напрямую. Вместо этого мы предоставляем FirebaseAuthProvider который инкапсулирует FirebaseAuthContext.Provider и подписку onAuthStateChanged. Это очень похоже на реализацию CurrentUser выше.

Теперь давайте определим простой хук, который дает компонентам, заинтересованным в аутентифицированном пользователе, доступ к нему:

// FirebaseAuthContext.tsx
// ...

function useFirebaseAuth() {
  const context = React.useContext(FirebaseAuthContext);
  if (context === undefined) {
    throw new Error(
      "useFirebaseAuth must be used within a FirebaseAuthProvider"
    );
  }
  return context.user;
}

export { FirebaseAuthProvider, useFirebaseAuth };

Наш хук useFirebaseAuth просто облегчает React.useContext для доступа к ранее определенному контексту. Мы тщательно проверяем undefined, чтобы как можно раньше выявить возможные злоупотребления.

FirebaseAuthProvider создается только один раз в приложении, обычно рядом с корнем, чтобы предоставить всем компонентам, расположенным ниже, возможность доступа к пользователю через useFirebaseAuth. Вот простой (надуманный) пример:

// example.ts
import * as React from "react";
import { FirebaseAuthProvider, useFirebaseAuth } from "./FirebaseAuthContext";

// ...initialize firebase

function App() {
  return (
    <FirebaseAuthProvider>
      <UserName />
      <UserEmail />
    </FirebaseAuthProvider>
  );
}

function UserName() {
  const user = useFirebaseAuth();
  return <div>{user?.displayName || "unauthenticated"}</div>;
}

function UserEmail() {
  const user = useFirebaseAuth();
  return <div>{user?.email || "-"}</div>;
}

Несколько замечаний:

  1. Инициализация Firebase не указана для краткости. Вы можете проверить её здесь, если вы еще этого не сделали.
  2. Хук может использоваться любым нижеуказанным компонентом FirebaseAuthProvider независимо от уровня вложенности.
  3. Каждое уведомление о onAuthStateChange запускает повторный рендеринг.
  4. Если ваше приложение управляет состоянием с помощью Redux или подобной библиотеки, вам может быть лучше обработать состояние аутентификации и там

Источник:

#React #TypeScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

Поделитесь своим опытом, расскажите о новом инструменте, библиотеке или фреймворке. Для этого не обязательно становится постоянным автором.

Попробовать

В подарок 100$ на счет при регистрации

Получить