Angular5:路由切换后ngOnInit仅触发一次致数据丢失问题求解
Ah, I've run into this exact issue with Angular routing before! The problem here is that Angular reuses component instances by default when navigating between routes. That means your ngOnInit hook only fires once when the component is first created, and doesn't trigger again when you navigate back to the Teams page later. Hence, your data doesn't reload, leaving you with an empty list until you refresh.
Here are a few solid solutions to fix this:
Solution 1: Force Component Reinitialization on Navigation
You can tell Angular to always recreate the Teams component whenever the route is visited by setting runGuardsAndResolvers: 'always' in your route configuration. This ensures ngOnInit runs every time you navigate to the page, reloading your data.
Update your routing module (e.g., app-routing.module.ts):
import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { TeamsComponent } from './components/teams/teams.component'; const routes: Routes = [ { path: 'teams', component: TeamsComponent, // Ensures the component is reinitialized on every navigation runGuardsAndResolvers: 'always' }, // Add other routes here... ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
Solution 2: Listen to Route Events to Reload Data Manually
If you prefer to reuse the component instance, you can subscribe to router navigation events and trigger a data reload whenever you return to the Teams page. This avoids recreating the component but still ensures fresh data.
Modify your TeamsComponent code:
import { Component, OnInit, OnDestroy } from '@angular/core'; import { TeamsService } from '../../services/teams.service'; import { Team } from '../../models/team'; import { Observable, Subscription } from 'rxjs'; import { Router, NavigationEnd } from '@angular/router'; import { filter } from 'rxjs/operators'; @Component({ selector: "app-teams", templateUrl: "./teams.component.html", styleUrls: ["./teams.component.css"] }) export class TeamsComponent implements OnInit, OnDestroy { public teams: Team[]; editState: boolean = false; teamToEdit: Team; showAdd: boolean = false; showSelect: boolean = false; selectedTeam: Observable<Team>; private routerSubscription: Subscription; constructor(public teamsService: TeamsService, private router: Router) { } ngOnInit() { // Load data on initial component load this.loadTeams(); // Listen for navigation end events to detect when we're back on the Teams page this.routerSubscription = this.router.events.pipe( filter(event => event instanceof NavigationEnd) ).subscribe((event: NavigationEnd) => { if (event.url.includes('/teams')) { this.loadTeams(); } }); } // Encapsulate data loading logic for reusability private loadTeams() { this.teamsService.getTeams().subscribe(teams => { this.teams = teams; console.log('Teams data reloaded'); }); } // Clean up subscription to prevent memory leaks ngOnDestroy() { if (this.routerSubscription) { this.routerSubscription.unsubscribe(); } } // Keep your existing methods: deleteTeam, editTeam, updateTeam, etc. }
Solution 3: Cache Data in the Service (Recommended)
The most elegant approach is to maintain your data state in the service using a BehaviorSubject. This way, the service holds the single source of truth for your teams data, and any component can subscribe to it to get the latest data—even when navigating back and forth.
First, update your TeamsService:
import { Injectable } from '@angular/core'; import { AngularFirestore } from '@angular/fire/firestore'; import { Team } from '../models/team'; import { BehaviorSubject, Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class TeamsService { // BehaviorSubject holds the current state of teams, with an empty array default private teamsSubject = new BehaviorSubject<Team[]>([]); // Expose an observable so components can subscribe without modifying the source public teams$: Observable<Team[]> = this.teamsSubject.asObservable(); constructor(private afs: AngularFirestore) { // Listen to Firestore changes and update the subject automatically this.afs.collection<Team>('teams').valueChanges().subscribe(teams => { this.teamsSubject.next(teams); }); } getTeamById(id: string): Observable<Team> { return this.afs.doc<Team>(`teams/${id}`).valueChanges(); } deleteTeam(team: Team) { return this.afs.doc(`teams/${team.id}`).delete(); } updateTeam(team: Team) { return this.afs.doc(`teams/${team.id}`).update(team); } // Add this if you need to create teams addTeam(team: Team) { return this.afs.collection('teams').add(team); } }
Then modify your TeamsComponent to subscribe to the service's observable:
import { Component, OnInit } from '@angular/core'; import { TeamsService } from '../../services/teams.service'; import { Team } from '../../models/team'; import { Observable } from 'rxjs'; @Component({ selector: "app-teams", templateUrl: "./teams.component.html", styleUrls: ["./teams.component.css"] }) export class TeamsComponent implements OnInit { public teams: Team[]; editState: boolean = false; teamToEdit: Team; showAdd: boolean = false; showSelect: boolean = false; selectedTeam: Observable<Team>; constructor(public teamsService: TeamsService) { } ngOnInit() { // Subscribe to the service's data stream to get real-time updates this.teamsService.teams$.subscribe(teams => { this.teams = teams; console.log('Received latest teams data'); }); } // Keep your existing methods unchanged }
This method has several benefits:
- It avoids redundant Firestore requests by keeping a cached copy of the data
- All components using the service will get consistent, up-to-date data
- You don't have to worry about route navigation affecting data availability
内容的提问来源于stack exchange,提问作者WestMD

