Angular 13获取API返回数据后如何实现答题应用核心逻辑
问题背景
- 有React开发经验,通过开发答题测验应用练习Angular,目前已调通API接口,控制台可正常打印返回的随机题目数组,但不清楚如何遍历数组实现逐题渲染、答对累计实时得分的核心答题逻辑
- 熟悉React「请求层存状态、props逐层传递到渲染组件」的开发模式,不清楚Angular的对应实现方案。当前项目组件层级为:发起API请求的组件是题目渲染组件的父组件,题目渲染组件又是答案渲染组件的父组件
- 对TypeScript语法不熟悉,不知道在
ngOnInit生命周期调用接口后,用什么语法持久存储接口返回的响应数据 - 不需要完整现成代码,仅需要核心实现思路、后续操作步骤指引
当前代码现存问题
shared/services/api.service.ts 现有代码
import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; @Injectable({ providedIn: 'root', }) export class apiService { constructor(private http: HttpClient) {} apiURL = 'http://localhost:8080'; httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json', }), }; getQuiz(category: any) { console.log('bacon'); return this.http.get(this.apiURL + '/quiz/' + category).subscribe((res) => { console.log(res); }) } }
问题点:getQuiz方法内部直接调用了.subscribe(),HTTP请求返回值被锁在service内部,调用方组件拿不到响应结果。
game-window.component.ts 现有代码
import { Component, OnInit } from '@angular/core'; import { apiService } from '../shared/services/api.service'; @Component({ selector: 'game-window', templateUrl: './game-window.component.html', styleUrls: ['./game-window.component.css'], }) export class GameWindowComponent implements OnInit { constructor(private _apiService: apiService ) { } ngOnInit() { this._apiService.getQuiz(window.location.pathname.split('/')[1]); } }
问题点:组件内没有定义存储题目列表、当前题目索引、得分的状态字段,也没有处理接口返回值的赋值逻辑。
核心实现思路&操作步骤
- 第一步:调整service层逻辑
把getQuiz方法里的.subscribe()逻辑删掉,直接返回this.http.get(...)生成的Observable对象即可,不要在service层处理订阅。这和React中请求工具函数只返回Promise、由调用组件自己处理结果的逻辑完全一致——如果在公共请求层直接订阅吞掉结果,上层组件拿不到返回值。 - 第二步:在父组件(GameWindowComponent)定义组件状态
和React需要用useState/this.setState管理状态不同,Angular类组件直接在类中、constructor外定义类属性就是持久化的响应式状态,直接给this.xxx赋值就会自动触发视图更新,不需要额外调用更新方法。你需要定义几个核心属性:quizList: any[] = []:存储接口返回的全部题目数组,TS里any[]的意思是任意类型的数组,刚上手不熟悉接口定义的时候可以先用any绕开类型校验currentIndex: number = 0:记录当前展示的题目序号,初始值0对应第一道题score: number = 0:存储实时累计得分- 可选加
loading: boolean = false控制请求中的加载态
- 第三步:在ngOnInit中订阅接口、给状态赋值
调用service的getQuiz方法后链式调用.subscribe(),在回调函数里把接口返回的题目数组赋值给this.quizList即可,这一步等价于React里拿到接口响应后调用setState更新题目列表。 - 第四步:父组件向题目渲染子组件传值
Angular父传子的实现和React props传递逻辑一致,语法上是在子组件标签上用方括号[]绑定要传递的属性。比如题目渲染组件的选择器是app-quiz-item,就在父组件模板里写<app-quiz-item [currentQuestion]="quizList[currentIndex]" [score]="score"></app-quiz-item>,子组件内部需要用*@Input()*装饰器声明要接收的属性,等价于React子组件接收props参数。 - 第五步:题目渲染组件向答案渲染孙组件传值
逻辑和上一步完全一致,题目组件拿到父组件传入的当前题目数据后,把题目内容、答案选项、正确答案标识等字段通过方括号绑定的方式传给答案组件即可。 - 第六步:实现答题交互逻辑
答案组件监听到用户点击选项的行为后,通过*@Output()*实例化的EventEmitter把用户选中的答案结果抛给上层组件,最终父组件监听事件判断答案是否正确:答对就给this.score加对应分值,然后把currentIndex加1切换到下一题,直到currentIndex等于题目总长度时跳转展示最终得分结果。这部分等价于React里子组件调用父组件传入的回调函数修改父组件状态的逻辑。 - 第七步:模板层做条件渲染
父组件模板里加判断逻辑:quizList长度为0时展示加载提示,currentIndex小于题目总长度时渲染题目组件,否则渲染得分结果页,和React里JSX写三元表达式做条件渲染的逻辑完全一致。
内容的提问来源于stack exchange,提问作者awkwardlynumb
相关产品推荐
相关产品推荐

