Декларативная выборка данных с React Async

Декларативная выборка данных с React Async

От автора: в JavaScript мы обычно используем async / await для асинхронных операций, таких как выборка данных. То же самое и при использовании библиотек пользовательского интерфейса, таких как React. Но что, если вместо этого вы получите возможность использовать компонент и хук React для извлечения данных?

React Async делает именно это, предоставляя компонентный подход для извлечения данных из API. В этой статье я расскажу о его основных функциях.

Введение в React-Async

React Async — это библиотека на основе промисов, которая предлагает декларативный API для выполнения вызовов API. Она предоставляет компонент React и хук для декларативного разрешения промисов и выборки данных.

React Async совместим практически со всеми библиотеками и API для извлечения данных, включая Fetch API, Axios и GraphQL. Кроме того, он также хорошо работает с React Native.

Установка React Async

Установить библиотеку React Async довольно просто. Вы можете обращаться с ней как с любой другой библиотекой JavaScript и устанавливать ее с помощью NPM или Yarn.

//NPM
npm install — save react-async //Yarn
yarn add react-async

У нее более 33 тысяч загрузок в неделю и 2 тысячи звезд на GitHub.

Примечание: не забудьте установить React как зависимость для этого пакета. Вам понадобится react @16.8.0 или выше, если вы хотите использовать хук useAsync.

Основы React Async

React Async — простая библиотека. Для начала вам необходимо ознакомиться с тремя основными API:

Компонент Async.

Хук useAsync.

Функция createInstance.

Итак, давайте подробно рассмотрим, что это за API и как они используются.

1. Компонент Async

Компонент Async — это классический интерфейс React Async, и мы можем использовать его, чтобы сделать компоненты React более декларативными. Мы можем напрямую использовать компонент Async в JSX для применения паттерна props. Ниже приведен простой пример использования компонента Async для получения данных.

import React, { Component } from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import Async from "react-async"; const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()); const App = () => ( <Async promiseFn={loadUsers}> {({ data, error, isLoading }) => { if (isLoading) return "Loading..."; if (error) return `Something went wrong: ${error.message}`; if (data) return ( <div> <h2>React Async - Users</h2> {data.map(el => ( <li> {el.name} --- {el.email} </li> ))} </div> ); return null; }} </Async>
); const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

В приведенном выше примере fetch API используется для выполнения вызова API внутри функции loadUsers. Он возвращает промис. И мы можем получить доступ к props из возвращаемых параметров промиса. Рrops выглядят следующим образом:

data: запрошенные данные с сервера.

error: для случаев, когда возникает ошибка.

isLoading: для сценариев, в которых ответ сервера еще не завершен.

С React Async нам не нужно использовать классы или методы жизненного цикла для извлечения данных и не нужно указывать, как обрабатывать данные.

2. Хук useAsync

Хук useAsync позволяет использовать базовые функции React Async непосредственно в функциональных компонентах. Если вам нравится использовать React Hooks, вы можете использовать useAsync Hook вместо компонента Async. В приведенном ниже примере показано, как мы можем использовать хук useAsync для извлечения данных.

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import { useAsync } from "react-async" const loadUsers = () => fetch("https://jsonplaceholder.typicode.com/users") .then(res => (res.ok ? res : Promise.reject(res))) .then(res => res.json()); const App = () => { const { data, error, isPending } = useAsync({ promiseFn: loadUsers, userId: 1 }) if (isPending) return "Loading..." if (error) return `Something went wrong: ${error.message}` if (data) return ( <div> <h2>React Async - Users</h2> {data.map(el => ( <li> {el.name} --- {el.email} </li> ))} </div> ) return null
} const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Как видите, я передал метод загрузки данных loadUsers в useAsync Hook. И вы можете получить доступ к результату, ошибкам или статусу с помощью props. Библиотека также предлагает еще один хук под названием useFetch, предназначенный для использования с Fetch API.

import { useFetch } from "react-async" const AppComponent = () => { const headers = { Accept: "application/json" } const { data, error, isPending, run } = useFetch("https://jsonplaceholder.typicode.com/users", { headers }, options) //A promiseFn with a fetch request and JSON deserialization will be created.
//You can then call 'run' with an optional callback argument to change the 'init' parameter provided to 'fetch' at the last minute. function clickHandler1() { run(init => ({ ...init, headers: { ...init.headers, authentication: "...", }, })) } //Instead, you can use an object that will be shared across 'init'.
//Note that this is not a deep merge, thus properties from the original 'init' parameter may be overridden. function clickHandler2() { run({ body: JSON.stringify(formValues) }) }
}

3. Функция createInstance()

React Async предлагает фабричную функцию createInstance(). Она позволяет создавать экземпляры компонентов с такими параметрами по умолчанию, как onResolve и onRejectcallbacks. В приведенном ниже примере показано, как мы можем создать собственный экземпляр Asynccomponent с помощью createInstance().

import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
import { createInstance } from "react-async" const loadUsers = async ({ id }) => { const res = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`) if (!res.ok) throw new Error(res.statusText) return res.json()
} const AsyncUser = createInstance({ promiseFn: loadUsers }, "AsyncUser") const App = () => ( <AsyncUser id={1}> <AsyncUser.Fulfilled>{user => `Hello ${user.name}`}</AsyncUser.Fulfilled> </AsyncUser> ) const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

По умолчанию createInstance() принимает два входных параметра: defaultOptions и displayName.

Функция loadUsers — defaultOption.

AsyncUser — отображаемое имя экземпляра.

Компоненты-помощники в React Async

Помимо компонента Async, React Async предоставляет несколько вспомогательных компонентов, чтобы сделать JSX более декларативным и понятным.

Эти вспомогательные компоненты могут принимать элемент React или функцию и включать или отключать рендеринг в зависимости от текущего состояния. Мы можем передать текущее состояние в useAsync или Async с помощью класса Context. Вот пример использования useAsync с хелперами. Это очень похоже на использование props.

import { useAsync, IfPending, IfFulfilled, IfRejected } from "react-async" const loadUsers = async ({id}) => { // ...
} const MyComponent = () => { const state = useAsync({ promiseFn: loadUsers, id: 1 }) return ( <> <IfPending state={state}>Loading...</IfPending> <IfRejected state={state}>{error => `Something went wrong: ${error.message}`}</IfRejected> <IfFulfilled state={state}> {data => ( <div> <strong>User data:</strong> {JSON.stringify(data,2)} </div> )} </IfFulfilled> </> )
}

В приведенном выше примере я использовал три вспомогательных компонента:

IfPending — отображается только пока промис находится в ожидании (загрузка / отключение).

IfRejected — отображается только в том случае, если промис отклонен.

IfFulfilled — отображается только тогда, когда промис выполнен (преобразовано в значение, может быть неопределенным).

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

Дополнительные возможности React Async

В React Async есть специальный пакет DevTools, который упрощает отладку и разработку асинхронных состояний приложения. Вы можете установить его с помощью NPM или Yarn:

//NPM
npm install --save react-async-devtools //Yarn
yarn add react-async-devtools

После установки вам необходимо импортировать его и отобразить компонент DevTools в корне вашего приложения следующим образом:

import DevTools from "react-async-devtools" export const Root = () => ( <> <DevTools /> <App /> </>
)

Кроме того, React Async предлагает множество вариантов конфигурации для обработки особых сценариев. Эти конфигурации могут быть отправлены как props в <Async {… options}> или как объект для useAsync (options). Некоторые из наиболее часто используемых вариантов конфигурации:

promise — уже запущенный экземпляр Promise.

promiseFn- функция, которая возвращает автоматически вызываемый промис.

initialValue — предоставляет исходные данные или ошибки для рендеринга на стороне сервера.

onResolve — обратный вызов, при разрешении Promise.

onReject — обратный вызов, при отклонении Promise.

onCancel — обратный вызов, при отмене обещания.

Заключение

В этой статье я обсудил, как использовать библиотеку React Async для декларативной выборки данных. Она нацелена на выборку данных как можно ближе к тому месту, где они будут использоваться, просто используя декларативный синтаксис и собственные промисы.

React Async эффективно работает даже в сложных приложениях с обширными зависимостями вложенных данных. Он способствует параллельной загрузке данных на уровне компонентов по запросу, а не массовой загрузки на более высоких уровнях маршрутизации страниц.

Кроме того, React Async был бы идеальным для больших приложений с динамической моделью маршрутизации или без маршрутов, поскольку он полностью не зависит от ваших маршрутов.

Спасибо за внимание!!

Автор: Piumi Liyana Gunawardhana

Источник: blog.bitsrc.io

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен