От автора: в 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, Яндекс.Дзен