Gestion d'État
Component State (Simple)
Section intitulée « Component State (Simple) »@Component({ selector: 'app-counter'})export class CounterComponent { count = 0; // Local state
increment() { this.count++; }}Signals (Modern)
Section intitulée « Signals (Modern) »import { Component, signal, computed } from '@angular/core';
@Component({ selector: 'app-todo-list'})export class TodoListComponent { todos = signal<Todo[]>([]); filter = signal<'all' | 'active' | 'completed'>('all');
filteredTodos = computed(() => { const filter = this.filter(); const todos = this.todos();
switch (filter) { case 'active': return todos.filter(t => !t.completed); case 'completed': return todos.filter(t => t.completed); default: return todos; } });
addTodo(title: string) { this.todos.update(todos => [ ...todos, { id: Date.now(), title, completed: false } ]); }
toggleTodo(id: number) { this.todos.update(todos => todos.map(t => t.id === id ? { ...t, completed: !t.completed } : t) ); }}Service-based State
Section intitulée « Service-based State »@Injectable({ providedIn: 'root' })export class UserService { private userSubject = new BehaviorSubject<User | null>(null); user$ = this.userSubject.asObservable();
private loadingSubject = new BehaviorSubject<boolean>(false); loading$ = this.loadingSubject.asObservable();
setUser(user: User) { this.userSubject.next(user); }
getUser(): Observable<User | null> { return this.user$; }
clearUser() { this.userSubject.next(null); }}
// Component usage@Component({})export class ProfileComponent { userService = inject(UserService); user$ = this.userService.user$;}Signal-based Service
Section intitulée « Signal-based Service »@Injectable({ providedIn: 'root' })export class TodoStore { private state = signal<TodoState>({ todos: [], filter: 'all', loading: false });
// Selecaurs todos = computed(() => this.state().todos); filter = computed(() => this.state().filter); loading = computed(() => this.state().loading);
filteredTodos = computed(() => { const todos = this.todos(); const filter = this.filter(); // Filter logic... return todos; });
// Actions addTodo(title: string) { this.state.update(state => ({ ...state, todos: [...state.todos, { id: Date.now(), title, completed: false }] })); }
setFilter(filter: 'all' | 'active' | 'completed') { this.state.update(state => ({ ...state, filter })); }
async loadTodos() { this.state.update(state => ({ ...state, loading: true })); try { const todos = await this.http.get<Todo[]>('/api/todos').toPromise(); this.state.update(state => ({ ...state, todos, loading: false })); } catch (error) { this.state.update(state => ({ ...state, loading: false })); } }}NgRx (Enterprise)
Section intitulée « NgRx (Enterprise) »Store Configuration
Section intitulée « Store Configuration »import { provideStore } from '@ngrx/store';import { provideEffects } from '@ngrx/effects';
export const appConfig: ApplicationConfig = { providers: [ provideStore({ todos: todoReducer }), provideEffects([TodoEffects]) ]};import { createAction, props } from '@ngrx/store';
export const loadTodos = createAction('[Todo] Load Todos');export const loadTodosSuccess = createAction( '[Todo] Load Todos Success', props<{ todos: Todo[] }>());export const addTodo = createAction( '[Todo] Add Todo', props<{ title: string }>());import { createReducer, on } from '@ngrx/store';
export interface TodoState { todos: Todo[]; loading: boolean;}
const initialState: TodoState = { todos: [], loading: false};
export const todoReducer = createReducer( initialState, on(loadTodos, state => ({ ...state, loading: true })), on(loadTodosSuccess, (state, { todos }) => ({ ...state, todos, loading: false })), on(addTodo, (state, { title }) => ({ ...state, todos: [...state.todos, { id: Date.now(), title, completed: false }] })));Selectors
Section intitulée « Selectors »import { createSelector, createFeatureSelector } from '@ngrx/store';
export const selectTodoState = createFeatureSelector<TodoState>('todos');
export const selectAllTodos = createSelector( selectTodoState, state => state.todos);
export const selectActiveTodos = createSelector( selectAllTodos, todos => todos.filter(t => !t.completed));
export const selectLoading = createSelector( selectTodoState, state => state.loading);import { Injectable } from '@angular/core';import { Actions, createEffect, ofType } from '@ngrx/effects';import { map, mergeMap, catchError } from 'rxjs/operators';
@Injectable()export class TodoEffects { actions$ = inject(Actions); todoService = inject(TodoService);
loadTodos$ = createEffect(() => this.actions$.pipe( ofType(loadTodos), mergeMap(() => this.todoService.getTodos().pipe( map(todos => loadTodosSuccess({ todos })), catchError(() => of(loadTodosFailure())) ) ) ) );}Component Utilisation
Section intitulée « Component Utilisation »import { Store } from '@ngrx/store';
@Component({})export class TodoListComponent { store = inject(Store);
todos$ = this.store.select(selectAllTodos); loading$ = this.store.select(selectLoading);
ngOnInit() { this.store.dispatch(loadTodos()); }
addTodo(title: string) { this.store.dispatch(addTodo({ title })); }}Comparison
Section intitulée « Comparison »| Approach | Best For | Complexity | Performance |
|---|---|---|---|
| Component State | Simple, isolated state | Low | Good |
| Signals | Local reactive state | Low | Excellent |
| Service + BehaviorSubject | Shsontd state | Medium | Good |
| Signal Service | Shsontd reactive state | Medium | Excellent |
| NgRx | Enterprise, complex apps | High | Excellent |
Bonnes Pratiques
Section intitulée « Bonnes Pratiques »Signal-based (Recommended for new apps)
Section intitulée « Signal-based (Recommended for new apps) »@Injectable({ providedIn: 'root' })export class AppStore { // Private state private state = signal<AppState>(initialState);
// Public selecaurs user = computed(() => this.state().user); isLoggedIn = computed(() => !!this.user());
// Actions (mutate state) login(user: User) { this.state.update(s => ({ ...s, user })); }
logout() { this.state.update(s => ({ ...s, user: null })); }}RxJS-based (Legacy apps)
Section intitulée « RxJS-based (Legacy apps) »@Injectable({ providedIn: 'root' })export class AppStore { private stateSubject = new BehaviorSubject<AppState>(initialState); private state$ = this.stateSubject.asObservable();
user$ = this.state$.pipe(map(s => s.user)); isLoggedIn$ = this.user$.pipe(map(u => !!u));
login(user: User) { const current = this.stateSubject.value; this.stateSubject.next({ ...current, user }); }}When to Use What
Section intitulée « When to Use What »- Component state: Simple, isolated features
- Signals: Moderne reactive local/shsontd state
- Service + BehaviorSubject: Legacy shsontd state
- NgRx: Large apps, complex state, team standards
- Component store (NgRx): Feature-specific state

