Atomico — это библиотека для создания веб-компонентов на базе JavaScript с реактивной моделью состояния. Загрузка данных в компонентах Atomico строится вокруг реактивных хуков и асинхронных функций, что позволяет создавать динамические интерфейсы без лишнего кода.
useState и
реактивное состояниеДля хранения загруженных данных используется хук
useState:
import { useState, c } from "atomico";
function UserList() {
const [users, setUsers] = useState([]);
return (
<host>
<ul>
{users.map(user => <li>{user.name}</li>)}
</ul>
</host>
);
}
customElements.define("user-list", c(UserList));
useState создаёт реактивное состояние, автоматически
обновляющее DOM при изменении значения. При загрузке данных важно
правильно инициализировать состояние, чтобы избежать ошибок доступа к
undefined при первом рендере.
useEffect
для побочных эффектовАсинхронная загрузка данных обычно выполняется внутри
useEffect, что позволяет запускать функции после
монтирования компонента:
import { useEffect, useState, c } from "atomico";
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchUsers() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/users");
const data = await response.json();
setUsers(data);
} catch (error) {
console.error(error);
} finally {
setLoading(false);
}
}
fetchUsers();
}, []);
return (
<host>
{loading ? <p>Загрузка...</p> : (
<ul>
{users.map(user => <li>{user.name}</li>)}
</ul>
)}
</host>
);
}
customElements.define("user-list", c(UserList));
useEffect с пустым массивом зависимостей []
гарантирует, что загрузка данных произойдёт только один раз после
первого рендера.
Для надёжной работы компонента рекомендуется хранить отдельные состояния:
loading — индикатор процесса загрузки.error — информация об ошибке.data — собственно, загруженные данные.const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
setLoading(true);
setError(null);
try {
const res = await fetch("/api/data");
if (!res.ok) throw new Error("Ошибка сети");
const result = await res.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}
fetchData();
}, []);
В JSX можно условно отображать различные состояния:
<host>
{loading && <p>Загрузка...</p>}
{error && <p style={{color: "red"}}>{error}</p>}
{!loading && !error && data.map(item => <div>{item.title}</div>)}
</host>
Atomico позволяет наблюдать за изменениями входных свойств компонента
через хук useWatch. Это особенно полезно для динамических
запросов:
import { useWatch, useState, useEffect, c } from "atomico";
function PostList({ userId }) {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
useWatch(() => {
if (!userId) return;
setLoading(true);
fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
.then(res => res.json())
.then(data => setPosts(data))
.finally(() => setLoading(false));
}, [userId]);
return (
<host>
{loading ? <p>Загрузка постов...</p> : (
<ul>{posts.map(post => <li>{post.title}</li>)}</ul>
)}
</host>
);
}
customElements.define("post-list", c(PostList));
useWatch реагирует на изменения массива зависимостей и
повторно запускает функцию загрузки, обеспечивая актуальные данные при
смене пропсов.
Для снижения количества сетевых запросов можно реализовать простое кеширование:
const cache = new Map();
useEffect(() => {
if (cache.has(userId)) {
setPosts(cache.get(userId));
setLoading(false);
return;
}
setLoading(true);
fetch(`https://jsonplaceholder.typicode.com/posts?userId=${userId}`)
.then(res => res.json())
.then(data => {
cache.set(userId, data);
setPosts(data);
})
.finally(() => setLoading(false));
}, [userId]);
Кеширование позволяет мгновенно отображать ранее загруженные данные, а асинхронный запрос выполняется только при необходимости.
При необходимости загрузки нескольких ресурсов одновременно
используется Promise.all:
useEffect(() => {
setLoading(true);
Promise.all([
fetch("/api/users").then(res => res.json()),
fetch("/api/posts").then(res => res.json())
]).then(([usersData, postsData]) => {
setUsers(usersData);
setPosts(postsData);
}).catch(err => setError(err.message))
.finally(() => setLoading(false));
}, []);
Это позволяет синхронизировать состояние нескольких источников данных и отображать их совместно в компоненте.
Чтобы избежать утечек памяти при быстром размонтировании компонентов,
можно использовать AbortController:
useEffect(() => {
const controller = new AbortController();
fetch("/api/data", { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== "AbortError") setError(err.message);
});
return () => controller.abort();
}, []);
Такой подход предотвращает обновление состояния размонтированного компонента и исключает ошибки.
useState для хранения данных, состояния
загрузки и ошибок.useEffect или
useWatch.Promise.all.AbortController.Эти подходы создают устойчивые и отзывчивые веб-компоненты на Atomico, готовые к работе с динамическими источниками данных.