You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 18.2.2 @If与Angular Material加载状态异常问题

解决Angular 18 SSR下表格加载状态反向显示问题

问题根源

SSR模式下,服务器端会预渲染组件的初始HTML。如果你的加载状态isLoading初始值设置错误,或者异步逻辑在服务器端被执行但未等待完成,就会出现初始显示表格、随后加载 spinner 消失的反向状态:

  • 若初始isLoading=false,服务器端直接渲染表格;客户端初始化后执行异步逻辑时才将isLoading设为true,导致短暂显示 spinner 后又隐藏。
  • 服务器端不会等待setTimeout或delay这类异步操作完成就输出HTML,导致客户端接管后状态逻辑混乱。

解决方案

1. 正确初始化加载状态

将isLoading初始值设为true,确保服务器端渲染时优先显示加载 spinner。

2. 限制异步逻辑仅在客户端执行

使用Angular 16+提供的afterNextRender钩子(或isPlatformBrowser判断),确保数据加载逻辑只在客户端执行,避免服务器端提前修改状态。

代码示例

组件实现

import { Component, afterNextRender } from '@angular/core';
import { MatTableModule } from '@angular/material/table';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { DataService } from './data.service';

@Component({
  selector: 'app-data-table',
  standalone: true,
  imports: [MatTableModule, MatProgressSpinnerModule],
  template: `
    @if (isLoading) {
      <div style="display: flex; justify-content: center; margin: 2rem;">
        <mat-spinner></mat-spinner>
      </div>
    } @else {
      <table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
        <!-- 表格列定义 -->
        <ng-container matColumnDef="id">
          <th mat-header-cell *matHeaderCellDef>ID</th>
          <td mat-cell *matCellDef="let item">{{ item.id }}</td>
        </ng-container>
        <ng-container matColumnDef="name">
          <th mat-header-cell *matHeaderCellDef>名称</th>
          <td mat-cell *matCellDef="let item">{{ item.name }}</td>
        </ng-container>

        <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
        <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
      </table>
    }
  `,
})
export class DataTableComponent {
  isLoading = true;
  dataSource: Array<{ id: number; name: string }> = [];
  displayedColumns = ['id', 'name'];

  constructor(private dataService: DataService) {
    // 仅在客户端首次渲染完成后执行加载逻辑
    afterNextRender(() => {
      this.dataService.getTableData().subscribe({
        next: (data) => {
          this.dataSource = data;
          this.isLoading = false;
        },
        error: () => {
          this.isLoading = false;
          // 可添加错误提示逻辑
        },
      });
    });
  }
}

数据服务实现

import { Injectable } from '@angular/core';
import { of, delay } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class DataService {
  getTableData() {
    // 模拟后端延迟响应
    return of([
      { id: 1, name: '测试数据1' },
      { id: 2, name: '测试数据2' },
    ]).pipe(delay(1000));
  }
}

关键说明

  • afterNextRender钩子:仅在客户端组件首次渲染完成后触发,完全避免服务器端执行异步加载逻辑,确保SSR输出的初始HTML是加载状态。
  • 初始isLoading=true:服务器端渲染时直接输出spinner,用户打开页面时首先看到加载状态,符合预期。

内容的提问来源于stack exchange,提问作者ArtO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 11:33:19