JavaRush /Курсы /Модуль 3: React /Создание HOC для проверки аутентификации и защиты компоне...

Создание HOC для проверки аутентификации и защиты компонентов

Модуль 3: React
4 уровень , 3 лекция
Открыта

Аутентификация и HOC: зачем это нужно?

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

Вместо того чтобы встраивать логику проверки аутентификации в каждый компонент (что приведёт к дублированию кода), мы можем создать HOC, который будет оборачивать защищённые компоненты, добавляя к ним проверку аутентификации.

Задачи HOC для защиты компонентов

  1. Проверить, авторизован ли пользователь.
  2. Если авторизован — отобразить защищённый компонент.
  3. Если не авторизован — перенаправить пользователя, например, на страницу входа.

Создание HOC для проверки аутентификации

Начнём с создания простого HOC для защиты компонентов. Вот как это может выглядеть на практике:

Стартовый код

Мы представим, что у нас уже есть функция isAuthenticated, которая проверяет, авторизован ли пользователь. Она возвращает true или false.

import React from 'react';
import { Navigate } from 'react-router-dom'; // Используем React Router для перенаправления

// Предположим, что эта функция проверяет, авторизован пользователь или нет.
const isAuthenticated = (): boolean => {
  return !!localStorage.getItem('token'); // Например, проверяем наличие токена в localStorage
};

Реализация самого HOC

Теперь создадим наш HOC. Он принимает компонент, который нужно защитить, оборачивает его логикой проверки и возвращает обновлённый компонент.

import React, { ComponentType } from 'react';
import { Navigate } from 'react-router-dom';

interface WithAuthProps {
  redirectPath?: string; // Вдруг мы захотим кастомный путь для редиректа
}

// HOC для защиты компонентов
function withAuth<T>(WrappedComponent: ComponentType<T>) {
  return (props: T & WithAuthProps) => {
    const { redirectPath = '/login' } = props;

    if (!isAuthenticated()) {
      // Если пользователь не авторизован, перенаправляем на страницу входа
      return <Navigate to={redirectPath} replace />;
    }

    // Если авторизован, рендерим исходный компонент
    return <WrappedComponent {...props} />;
  };
}

export default withAuth;

Разбор кода

  1. Типизация с TypeScript: ComponentType<T> позволяет нам работать с любым типом компонента. Мы добавили пропсы через <T> для типизации передаваемых данных.
  2. redirectPath: опциональное значение для кастомизации пути перенаправления.
  3. Navigate: это компонент из react-router-dom, который перенаправляет пользователя.

Пример использования HOC в приложении

Теперь давайте подключим наш HOC к реальному компоненту.

import React from 'react';
import withAuth from './withAuth';

const Dashboard: React.FC = () => {
  return <h1>Добро пожаловать в личный кабинет!</h1>;
};

// Оборачиваем компонент HOC'ом
export default withAuth(Dashboard);
 

Когда пользователь попытается зайти на страницу Dashboard, HOC сначала проверит, авторизован ли он. В случае отсутствия авторизации его перенаправит на /login.

Типизация пропсов защищённого компонента

Когда мы работаем с HOC, важно правильно типизировать как входящие пропсы (то, что передаётся в HOC), так и пропсы самого оборачиваемого компонента. Давайте расширим наш HOC, чтобы более детально рассмотреть типизацию.

function withAuth<T extends object>(
  WrappedComponent: ComponentType<T>
) {
  return (props: T & WithAuthProps) => {
    const { redirectPath = '/login' } = props;

    if (!isAuthenticated()) {
      return <Navigate to={redirectPath} replace />;
    }

    return <WrappedComponent {...props} />;
  };
}

Разбор кода

  • Здесь мы добавили T extends object — это ограничение, которое говорит, что HOC может работать только с объектами. Это общее правило для большинства компонентов React.
  • ComponentType<T> позволяет HOC работать как с функциональными, так и с классовыми компонентами.

Поддержка дополнительных пропсов

Если у вас компонент, который принимает специфические пропсы, вы можете обеспечить их поддержку через расширение интерфейсов. Например:

interface DashboardProps {
  username: string;
}

// Это защищённый компонент с пропсом username
const Dashboard: React.FC<DashboardProps> = ({ username }) => {
  return <h1>Добро пожаловать, {username}!</h1>;
};

// Оборачиваем Dashboard, не забывая, что HOC должен поддерживать все пропсы
const ProtectedDashboard = withAuth(Dashboard);

// Используем так:
<ProtectedDashboard username="Alice" />;

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

Расширение функциональности HOC

HOC можно дополнить, чтобы он мог выполнять больше задач. Например, добавим поддержку отображения загрузочного индикатора, пока идёт проверка аутентификации.

function withAuth<T>(WrappedComponent: ComponentType<T>) {
  return (props: T & WithAuthProps) => {
    const [loading, setLoading] = React.useState(true);

    React.useEffect(() => {
      // Эмуляция проверки авторизации
      setTimeout(() => setLoading(false), 1000);
    }, []);

    if (loading) {
      return <div>Загрузка...</div>;
    }

    if (!isAuthenticated()) {
      return <Navigate to="/login" replace />;
    }

    return <WrappedComponent {...props} />;
  };
}

Теперь HOC покажет текст "Загрузка...", пока проверяет авторизацию.

Типичные ошибки и способы их избежать

При реализации HOC могут возникать ошибки, особенно связанные с типизацией и неправильной передачей пропсов. Вот пару моментов:

  1. Пропсы теряются при оборачивании. Если в HOC используются специфические пропсы оригинального компонента, убедитесь, что они корректно типизированы и передаются через ...props.
  2. Поломка контекста. Если оборачиваемый компонент использует React Context, проверьте, что HOC не ломает доступ к контексту. Используйте React.forwardRef, если нужно сохранить ссылки.

Практическое применение

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

1
Задача
Модуль 3: React, 4 уровень, 3 лекция
Недоступна
Простая реализация HOC для защиты компонента
Простая реализация HOC для защиты компонента
1
Задача
Модуль 3: React, 4 уровень, 3 лекция
Недоступна
Защита компонента с редиректом
Защита компонента с редиректом
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ