Riot.js предоставляет гибкий подход к управлению состоянием компонентов и асинхронными операциями, включая загрузку данных и отображение индикаторов прогресса. В основе лежит реактивность компонентов, что позволяет синхронизировать интерфейс с состоянием приложения без сложного вмешательства в DOM.
В Riot.js асинхронные операции обычно выполняются в методах
жизненного цикла компонента, таких как mounted() или
onBeforeMount(). Для загрузки данных используют стандартные
возможности JavaScript — fetch, axios или
другие HTTP-клиенты.
Пример загрузки данных через fetch:
<user-list>
<ul>
<li each={user in users}>{user.name}</li>
</ul>
<script>
export default {
users: [],
loading: true,
async onBeforeMount() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
this.users = data;
} catch (error) {
console.error('Ошибка при загрузке данных:', error);
} finally {
this.loading = false;
}
}
}
</script>
</user-list>
В этом примере:
users — реактивное свойство, автоматически обновляющее
DOM при изменении.loading — флаг состояния загрузки, который можно
использовать для отображения индикатора прогресса.async onBeforeMount() гарантирует, что данные начнут
загружаться перед рендером компонента.Отображение индикаторов прогресса связано с состоянием компонента.
Riot.js поддерживает условный рендеринг с использованием директив
if и show.
Пример использования индикатора:
<user-list>
<div if={loading}>Загрузка данных...</div>
<ul if={!loading}>
<li each={user in users}>{user.name}</li>
</ul>
<script>
export default {
users: [],
loading: true,
async onBeforeMount() {
try {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
this.users = data;
} catch (error) {
console.error('Ошибка при загрузке данных:', error);
} finally {
this.loading = false;
}
}
}
</script>
</user-list>
Использование if позволяет скрывать список до завершения
загрузки и показывать индикатор только при активной асинхронной
операции. Для более сложных сценариев, например прогресса загрузки по
частям, можно использовать динамическое обновление свойства
progress и визуальные элементы типа полосы загрузки.
Для реализации полосы прогресса можно создать отдельный компонент:
<progress-bar>
<div class="progress-container">
<div class="progress" style="width: {progress}%"></div>
</div>
<script>
export default {
progress: 0
}
</script>
<style>
.progress-container {
width: 100%;
background: #f0f0f0;
height: 8px;
border-radius: 4px;
overflow: hidden;
}
.progress {
height: 100%;
background: #4caf50;
transition: width 0.3s ease;
}
</style>
</progress-bar>
В родительском компоненте:
<user-loader>
<progress-bar progress={progress}></progress-bar>
<ul if={!loading}>
<li each={user in users}>{user.name}</li>
</ul>
<script>
import ProgressBar from './progress-bar.riot';
export default {
users: [],
loading: true,
progress: 0,
async onBeforeMount() {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const reader = response.body.getReader();
const contentLength = +response.headers.get('Content-Length');
let receivedLength = 0;
let chunks = [];
while(true) {
const {done, value} = await reader.read();
if(done) break;
chunks.push(value);
receivedLength += value.length;
this.progress = Math.round((receivedLength / contentLength) * 100);
}
const chunksAll = new Uint8Array(receivedLength);
let position = 0;
for(let chunk of chunks) {
chunksAll.set(chunk, position);
position += chunk.length;
}
const result = new TextDecoder("utf-8").decode(chunksAll);
this.users = JSON.parse(result);
this.loading = false;
}
}
</script>
</user-loader>
Данный подход обеспечивает плавное обновление полосы прогресса в реальном времени при поступлении данных по частям, сохраняя реактивность интерфейса.
Riot.js совместим с внешними библиотеками, такими как
axios и nprogress. Для интеграции достаточно
управлять состоянием компонентов через методы жизненного цикла и
реактивные свойства:
import axios from 'axios';
import NProgress from 'nprogress';
export default {
users: [],
loading: false,
async onBeforeMount() {
NProgress.start();
this.loading = true;
try {
const {data} = await axios.get('https://jsonplaceholder.typicode.com/users');
this.users = data;
} catch (error) {
console.error(error);
} finally {
this.loading = false;
NProgress.done();
}
}
}
Такой подход упрощает реализацию индикаторов прогресса без необходимости ручного управления состояниями загрузки.
Ключевой особенностью Riot.js является реактивность, позволяющая связывать состояние загрузки, прогресс и контент напрямую с DOM. Это делает компоненты:
Использование реактивных свойств loading,
progress и массивов данных позволяет создавать интерфейсы с
плавными переходами и визуальной обратной связью без сложных структур и
дополнительных библиотек.