Angular est-il vraiment plus compliqué que React ?

Quand on débute avec Angular, il est facile de se sentir découragé face à la multitude de concepts à assimiler. Cette complexité peut inciter à se tourner vers des frameworks comme React, qui semblent plus simples à première vue. Mais est-ce vraiment le cas ?

Abonnez-vous à notre chaîne

Pour profiter des prochaines vidéos sur Angular, abonnez-vous à la nouvelle chaîne YouTube !

Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

Comment utiliser useFactory dans Angular pour créer des services configurables ?

useFactory est une fonctionnalité puissante d'Angular qui permet de créer des instances de services de manière dynamique et configurable. C'est particulièrement utile quand la création d'un service nécessite une logique complexe ou des paramètres qui ne sont connus qu'à l'exécution.

Comprendre useFactory avec un exemple concret

Imaginons que vous développez une application de messagerie instantanée :

  1. En production :

    • Connexion au serveur de production
    • Messages en temps réel
    • Notifications push
  2. En développement :

    • Connexion au serveur local
    • Délai simulé pour les messages
    • Notifications console

useFactory nous permet de configurer notre service de messagerie différemment selon l'environnement, tout en gardant la même interface d'utilisation.

Différences avec les autres providers

ProviderDescriptionExempleCas d'utilisationDocumentation
useClassRemplace complètement un service par une autre classe{ provide: UserService, useClass: MockUserService }Quand vous voulez une implémentation complètement différente (ex: mock pour les tests)En savoir plus
useValueFournit une valeur fixe{ provide: API_URL, useValue: 'https://api.example.com' }Pour des constantes ou des objets simples prédéfinisEn savoir plus
useFactoryCrée dynamiquement une valeur via une fonction{ provide: UserService, useFactory: () => environment.production ? new RealUserService() : new MockUserService() }Quand la valeur dépend de conditions ou nécessite une logique de créationEn savoir plus
useExistingCrée un alias vers un service existant{ provide: AbstractLogger, useExisting: ConsoleLogger }Quand vous voulez utiliser un service existant sous un autre nomEn savoir plus

Mise en pratique avec notre gestionnaire d'utilisateurs

Voici comment implémenter un service d'utilisateurs configurable :

ts
import { HttpClient } from '@angular/common/http';
import { UserService } from './user.service';

export function userServiceFactory(http: HttpClient, environment: string) {
  const config = {
    production: {
      apiUrl: 'https://api.example.com/users',
      cacheTimeout: 3600000 // 1 heure
    },
    development: {
      apiUrl: 'http://localhost:3000/users',
      cacheTimeout: 0 // pas de cache en dev
    }
  };

  const env = environment === 'production' ? 'production' : 'development';
  return new UserService(
    http,
    config[env].apiUrl,
    config[env].cacheTimeout
  );
}
ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { User } from './user';
import { Observable } from 'rxjs';

@Injectable()
export class UserService {
  constructor(
    private http: HttpClient,
    private apiUrl: string,
    private cacheTimeout: number
  ) {}

  getUsers(): Observable<User[]> {
    return this.http.get<User[]>(this.apiUrl);
  }
}
ts
export interface User {
    id: number;
    name: string;
    username?: string;
    email: string;
    address?: {
        street: string;
        suite: string;
        city: string;
        zipcode: string;
        geo: {
            lat: string;
            lng: string;
        }
    };
    phone?: string;
    website?: string;
    company?: {
        name: string;
        catchPhrase: string;
        bs: string;
    };
}

CONSEIL

Une factory function permet d'encapsuler toute la logique de création et de configuration d'un service dans un seul endroit, rendant le code plus maintenable.

Configuration du provider dans votre application :

ts
import { ApplicationConfig } from '@angular/core';
import { UserService } from './user.service';
import { userServiceFactory } from './user.factory';
import { ENVIRONMENT } from './environment.token';

export const appConfig: ApplicationConfig = {
  providers: [
    {
      provide: ENVIRONMENT,
      useValue: 'production' // ou process.env.NODE_ENV
    },
    {
      provide: UserService,
      useFactory: userServiceFactory,
      deps: [HttpClient, ENVIRONMENT]
    }
  ]
};
ts
import { InjectionToken } from '@angular/core';

export const ENVIRONMENT = new InjectionToken<string>('environment');

Pour comprendre simplement :

typescript
{
  provide: UserService,           // "Je veux un service utilisateur"
  useFactory: userServiceFactory, // "Utilise cette fonction pour le créer"
  deps: [HttpClient, ENVIRONMENT] // "Voici ce dont tu as besoin pour le créer"
}

IMPORTANT

La propriété deps doit contenir tous les services et valeurs nécessaires à votre factory function, dans le même ordre que les paramètres de la fonction.

Rappel

Un InjectionToken est un token unique qui permet d'injecter des valeurs qui ne sont pas des classes. C'est particulièrement utile pour :

  • Injecter des valeurs primitives (string, number, etc.)
  • Éviter les collisions de noms
  • Typer correctement les dépendances injectées

En savoir plus : InjectionToken

IMPORTANT

Dans un vrai projet, la valeur de l'environnement devrait venir de vos fichiers d'environnement Angular (environment.ts et environment.prod.ts) ou de variables d'environnement.

En savoir plus : Environnement

Cas d'utilisation typiques

  1. Configuration dynamique :

    • URLs différentes selon l'environnement
    • Timeouts configurables
    • Stratégies de cache adaptatives
  2. Logique conditionnelle :

    • Différentes implémentations selon les features flags
    • Adaptation selon la plateforme (web/mobile)
    • Comportements spécifiques selon l'utilisateur
  3. Tests :

    • Configuration spécifique pour les tests
    • Injection de mocks avec paramètres
    • Simulation de scénarios complexes

BONNE PRATIQUE

Pour les tests, vous pouvez créer une factory spécifique :

ts
export function testUserServiceFactory(http: HttpClient) {
  return new UserService(
    http,
    'http://test-api/users',
    0
  );
}

TestBed.configureTestingModule({
  providers: [
    {
      provide: UserService,
      useFactory: testUserServiceFactory,
      deps: [HttpClient]
    }
  ]
});

Chaque mois, recevez en avant-première notre newsletter avec les dernières actualités, tutoriels, astuces et ressources Angular directement par email !