Angular嵌套*ngFor触发无限循环问题(Github仓库查看器场景)
Angular + GitHub API:解决仓库语言列表无限循环与展示异常问题
问题根源
- 模板调用函数触发无限循环:在
*ngFor中直接调用languagesUsed(repo.name),Angular的变更检测机制会在每次检测周期执行这个函数。每次调用都会发起新的HTTP请求,请求完成后修改全局变量langs又会触发变更检测,形成无限循环。 - 全局变量导致语言列表混乱:所有仓库共用同一个
langs数组,每个仓库的语言请求返回后都会覆盖这个数组,最终所有仓库显示的都是最后一次请求的语言结果,无法独立展示各仓库的语言。
解决方案
1. 调整组件逻辑,为每个仓库绑定专属语言列表
修改Component.ts,移除全局langs数组,在获取仓库列表后,为每个仓库单独请求语言并存储到自身属性中:
export class UserComponentComponent implements OnInit { @Input() username:any; constructor(private githubUser:UserDataService) { } repos:Array<any> = []; avatar:any; name:String = ''; location:String = ''; bio:String = ''; twitter:String = ''; github:String = ''; totalRecords = 0; page = 1; // 移除全局langs数组 getUser(){ this.githubUser.getData(this.username).subscribe((data)=>{ this.avatar = data.avatar_url; this.name = data.name; this.location = data.location; this.bio = data.bio; this.twitter = `https://twitter.com/${data.twitter_username}`; this.github = `https://github.com/${data.login}`; }) } getRepos(){ this.githubUser.getRepositories(this.username).subscribe((repos)=>{ this.repos = repos; this.totalRecords = repos?.length; // 为每个仓库请求语言并绑定到自身属性 repos.forEach(repo => { this.githubUser.getLanguages(this.username, repo.name).subscribe(languages => { repo.languages = Array.from(Object.keys(languages)); }); }); // 【可选优化】用forkJoin批量请求,减少订阅次数 // import { forkJoin } from 'rxjs'; // import { map } from 'rxjs/operators'; // const languageRequests = repos.map(repo => // this.githubUser.getLanguages(this.username, repo.name).pipe( // map(langs => ({ repo, langs: Array.from(Object.keys(langs)) })) // ) // ); // forkJoin(languageRequests).subscribe(results => { // results.forEach(item => item.repo.languages = item.langs); // }); }) } // 移除原languagesUsed函数 ngOnInit(): void{ this.getUser(); this.getRepos(); } }
2. 修改模板,直接遍历仓库的专属语言列表
修改HTML模板,不再调用函数,直接访问每个仓库的languages属性,同时添加*ngIf避免未加载完成时的报错:
<div class="user-repos"> <ul id="repos" *ngFor="let repo of repos | paginate:{ id:'listing_repos',itemsPerPage:10, currentPage:page, totalItems:totalRecords}"> <li> <h4>{{ repo.name | uppercase}}</h4> <p>{{ repo.description }}</p> <ul *ngIf="repo.languages"> <li *ngFor="let lang of repo.languages">{{lang}}</li> </ul> </li> </ul> </div>
3. 额外优化建议
- 添加加载状态:可以给每个仓库对象添加
isLoading属性,在请求语言时显示加载提示,提升用户体验 - 实现缓存机制:创建一个
languageCache对象存储已请求过的仓库语言,避免分页切换时重复发起API请求
内容的提问来源于stack exchange,提问作者Manan Sharma
相关产品推荐
相关产品推荐

