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

DI в React, но не тот, о котором подумали

·251 слово·2 минут·
Александр Мунько
Автор
Александр Мунько
Любитель порассказывать про Фронтенд
Оглавление
Оригинальная статья

Зачем Dependency Inversion в React
#

В мире разработки на React’е мы очень часто пишем компоненты, которые тесно связаны, но потом обнаруживаем, что такие компоненты тяжело тестировать, поддерживать и изменять.

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

  • тесная связь кода с API-слоём;
  • сложность тестирования вызовов API;
  • трудности в изменении источника данных;
  • сложности с пониманием состояния запросов и т.д.

Пример инверсии зависимостей
#

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

interface UserRepository {
  getUser: () => Promise<User>;
}

class ApiUserRepository implements UserRepository {
  async getUser(): Promise<User> {
    const response = await fetch("/api/user");
    return response.json();
  }
}

class MockUserRepository implements UserRepository {
  private userPromiseWithResolvers?: PromiseWithResolvers<User>;

  getUser(): Promise<User> {
    this.userPromiseWithResolvers = Promise.withResolvers();
    return this.userPromiseWithResolvers.promise;
  }

  // Метод для резолва промиса
  resolveWithUser(user: User) {
    this.userPromiseWithResolvers?.resolve(user);
  }

  // Метод для реджекта промиса
  rejectUser(error: Error) {
    this.userPromiseWithResolvers?.reject(error);
  }
}

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

Мысли

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

Выводы
#

Из статьи можно вынести лучшие практики:

  • необходимо определять четкие интерфейсы, представляющие зависимости в проекте;
  • использовать экземпляры интерфейсов через пропы или контекст (или через тот самый DI – TSyringe);
  • писать легко тестируемые компоненты с изолированными тестами.