Работа с REST API и GraphQL

Riot.js — легковесный и высокопроизводительный фреймворк для создания интерфейсов на JavaScript. Основная сила Riot заключается в его реактивной системе и простоте компонентов. При взаимодействии с внешними источниками данных, такими как REST API и GraphQL, фреймворк предоставляет удобные механизмы для асинхронного обновления состояния компонентов.


Подключение и настройка HTTP-запросов

Для работы с REST API и GraphQL в Riot.js обычно используют встроенные возможности fetch или сторонние библиотеки вроде axios. Riot.js не накладывает ограничений на выбор инструмента, так как основной акцент сделан на компонентной архитектуре и реактивности.

Пример базовой настройки fetch:

async function getData(url) {
  try {
    const response = await fetch(url, { method: 'GET' });
    if (!response.ok) throw new Error(`Ошибка: ${response.status}`);
    return await response.json();
  } catch (error) {
    console.error(error);
  }
}

При работе с GraphQL запросы чаще всего отправляются методом POST, а тело запроса содержит объект с полем query и, при необходимости, variables.

async function fetchGraphQL(query, variables = {}) {
  const response = await fetch('https://api.example.com/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query, variables })
  });
  const result = await response.json();
  if (result.errors) console.error(result.errors);
  return result.data;
}

Интеграция REST API в компоненты Riot.js

Компоненты Riot.js строятся вокруг реактивного состояния, что позволяет легко синхронизировать данные, полученные с сервера, с DOM.

Пример компонента, получающего список пользователей с REST API:

<user-list>
  <ul>
    <li each={user in users}>{user.name}</li>
  </ul>

  <script>
    import { onMounted, reactive } from 'riot';

    const state = reactive({ users: [] });

    async function fetchUsers() {
      state.users = await getData('https://jsonplaceholder.typicode.com/users');
    }

    onMounted(() => {
      fetchUsers();
    });

    export default { users: state.users };
  </script>
</user-list>

Ключевой момент — использование реактивного объекта state. Любое изменение массива users автоматически обновляет DOM благодаря реактивной системе Riot.js.


Использование GraphQL в компонентах

GraphQL позволяет более гибко управлять данными, запрашивая только необходимые поля. В Riot.js это удобно комбинировать с реактивным состоянием.

Пример запроса пользователей с GraphQL:

<graphql-user-list>
  <ul>
    <li each={user in users}>{user.name} ({user.email})</li>
  </ul>

  <script>
    import { onMounted, reactive } from 'riot';

    const state = reactive({ users: [] });

    const query = `
      query {
        users {
          id
          name
          email
        }
      }
    `;

    async function fetchUsers() {
      state.users = await fetchGraphQL(query);
    }

    onMounted(() => {
      fetchUsers();
    });

    export default { users: state.users };
  </script>
</graphql-user-list>

Реактивность обеспечивает мгновенное обновление интерфейса при изменении данных. GraphQL сокращает объём передаваемой информации и упрощает управление сложными структурами данных.


Обработка ошибок и состояние загрузки

Для пользовательского опыта важно отображать статус загрузки и обрабатывать ошибки. Riot.js позволяет это делать через реактивные переменные состояния:

<user-list>
  <div if={loading}>Загрузка...</div>
  <div if={error}>Ошибка: {error}</div>
  <ul if={!loading && !error}>
    <li each={user in users}>{user.name}</li>
  </ul>

  <script>
    import { onMounted, reactive } from 'riot';

    const state = reactive({ users: [], loading: true, error: null });

    async function fetchUsers() {
      try {
        state.loading = true;
        state.users = await getData('https://jsonplaceholder.typicode.com/users');
      } catch (e) {
        state.error = e.message;
      } finally {
        state.loading = false;
      }
    }

    onMounted(() => {
      fetchUsers();
    });

    export default { ...state };
  </script>
</user-list>

Такой подход обеспечивает чистую реактивную интеграцию API без необходимости дополнительных библиотек для управления состоянием.


Взаимодействие с динамическими параметрами

REST и GraphQL часто требуют передачи динамических параметров, например идентификаторов ресурсов или фильтров.

REST пример:

async function fetchUserById(id) {
  return await getData(`https://jsonplaceholder.typicode.com/users/${id}`);
}

GraphQL пример с переменными:

const query = `
  query getUser($id: ID!) {
    user(id: $id) {
      id
      name
      email
    }
  }
`;

async function fetchUser(id) {
  return await fetchGraphQL(query, { id });
}

Комбинируя это с реактивным состоянием в Riot.js, можно создавать компоненты с динамическими запросами и мгновенно отображать результаты.


Рекомендации по оптимизации

  • Использовать реактивные объекты для хранения всех данных компонента, чтобы обновления интерфейса происходили автоматически.
  • Для частых запросов применять кеширование, например через локальные переменные или библиотеки вроде swr/react-query в интеграции с Riot.js.
  • Обрабатывать ошибки и состояния загрузки, чтобы интерфейс оставался отзывчивым.
  • В GraphQL запрашивать только необходимые поля для уменьшения нагрузки на сеть и ускорения рендеринга.

Асинхронные события и взаимодействие компонентов

Riot.js позволяет связывать события и асинхронные действия между компонентами:

<parent-component>
  <child-component on:userLoaded={handleUserLoaded}></child-component>

  <script>
    function handleUserLoaded(user) {
      console.log('Пользователь загружен:', user);
    }
  </script>
</parent-component>

Внутри дочернего компонента можно вызывать this.trigger('userLoaded', user) после получения данных из REST или GraphQL, обеспечивая реактивное взаимодействие компонентов.


Такой подход обеспечивает чистое разделение логики и представления, упрощает работу с асинхронными данными и позволяет создавать масштабируемые интерфейсы с использованием Riot.js и современных API.