48 lines
1.2 KiB
Markdown
48 lines
1.2 KiB
Markdown
---
|
|
title: Use Loading Substates for Better UX
|
|
impact: CRITICAL
|
|
impactDescription: Perceived performance improvement
|
|
tags: routes, loading, ux, performance
|
|
---
|
|
|
|
## Use Loading Substates for Better UX
|
|
|
|
Implement loading substates to show immediate feedback while data loads, preventing blank screens and improving perceived performance.
|
|
|
|
**Incorrect (no loading state):**
|
|
|
|
```javascript
|
|
// app/routes/posts.js
|
|
export default class PostsRoute extends Route {
|
|
async model() {
|
|
return this.store.request({ url: '/posts' });
|
|
}
|
|
}
|
|
```
|
|
|
|
**Correct (with loading substate):**
|
|
|
|
```glimmer-js
|
|
// app/routes/posts-loading.gjs
|
|
import { LoadingSpinner } from './loading-spinner';
|
|
|
|
<template>
|
|
<div class="loading-spinner" role="status" aria-live="polite">
|
|
<span class="sr-only">Loading posts...</span>
|
|
<LoadingSpinner />
|
|
</div>
|
|
</template>
|
|
```
|
|
|
|
```javascript
|
|
// app/routes/posts.js
|
|
export default class PostsRoute extends Route {
|
|
model() {
|
|
// Return promise directly - Ember will show posts-loading template
|
|
return this.store.request({ url: '/posts' });
|
|
}
|
|
}
|
|
```
|
|
|
|
Ember automatically renders `{route-name}-loading` route templates while the model promise resolves, providing better UX without extra code.
|