От автора: одна из проблем, с которыми мы сталкиваемся при создании приложения с помощью React — это определение шаблона кода для выборки данных с сервера. Наиболее распространенный способ обработки выборки данных в React — использование глобального состояния в качестве механизма для определения текущего статуса операции выборки.
Вот пример получения данных из Star Wars API:
import React, {useState, useEffect} from 'react'; import axios from 'axios';// regular fetch with axios function App() { const [isLoading, setLoading] = useState(false) const [isError, setError] = useState(false) const [data, setData] = useState({}); useEffect(() => { const fetchData = async () => { setError(false); setLoading(true); try { const response = await axios('http://swapi.dev/api/people/1/'); setData(response.data); } catch (error) { setError(true); } setLoading(false); }; fetchData() }, []); return ( <div className="App"> <h1>React Query example with Star Wars API</h1> {isError && <div>Something went wrong ...</div>} {isLoading ? ( <div>Loading ...</div> ) : ( {JSON.stringify(data, null, 2)} )} </div> ); } export default App;
В приведенном выше коде подключаются хуки useState и useEffect, и используются три разных состояния для хранения данных и определения, извлекает ли приложение данные или уже имеет ответ об ошибке от API. Этот шаблон повторяется снова и снова для большей части логики выборки данных приложения.
И это еще не все. Наиболее распространенные проблемы с получением данных в React включают:
Данные доступны для всех экземпляров приложения и могут быть изменены другими людьми.
Данные могут быть «устаревшими», и их необходимо обновить.
Обработка кеширования и аннулирования данных для оптимизации операции запроса
Наконец, существует также проблема наличия локального состояния, в котором обычно хранятся настройки пользователя, такие как тема и конфигурация боковой панели, в сочетании с удаленным состоянием, в котором хранятся данные, полученные из API:
//what global state commonly look like nowadays const state = { theme: "light", sidebar: "off", followers: [], following: [], userProfile: {}, messages:[], todos:[], }
Было бы неплохо, если бы вы могли отделить локальное состояние от удаленного? А что, если вы можете уменьшить объем шаблонного кода, который вам нужно написать для выборки данных?
Одним из решений может быть создание собственного пользовательского хука для обработки выборки и данных. Это вполне правильное решение. Вы также можете поделиться этим хуком и управлять им в хабе компонентов, таком как Bit (Github). Таким образом, он будет доступен для любого проекта, над которым вы работаете (это может быть как простой хук, так и часть других повторно используемых «интеллектуальных компонентов»).
Пример: просмотр общих компонентов React на Bit.dev
Еще одно решение, которое мы рассмотрим здесь подробно — это React Query. Эта библиотека поможет вам извлекать, синхронизировать, обновлять и кэшировать удаленные данные, а также сократить объем кода, который вам нужно написать, предоставляя два простых хука и одну служебную функцию.
Чтобы получить максимальную отдачу от этой статьи, загрузите этот образец репозитория, который я изменил от автора:
Пример приложения React Query
Это небольшое приложение React будет извлекать массив строк из маршрута API с помощью axios. Вы можете поместить новую строку в массив, используя предоставленную форму. В нем также открыт React Query DevTools, чтобы вы могли видеть кэшированные данные в режиме реального времени.
Хук useQuery
Хук useQuery — это функция, которая используется для регистрации кода выборки данных в библиотеке React Query. Он принимает произвольный ключ и асинхронную функцию для выборки данных и возвращает различные значения, которые вы можете использовать для информирования пользователей о текущем состоянии приложения.
Например, давайте реорганизуем приведенный выше пример Star Wars API:
import React from 'react'; import axios from 'axios'; import {useQuery} from 'react-query';// react-query fetch with axios function App() { const { isLoading, error, data } = useQuery('fetchLuke', () => axios('http://swapi.dev/api/people/1/')) return ( <div className="App"> <h1>React Query example with star wars API</h1> {error && <div>Something went wrong ...</div>} {isLoading ? ( <div>Retrieving Luke Skywalker Information ...</div> ) : ( {JSON.stringify(data, null, 2)} )} </div> ); } export default App;
Обратите внимание, что в этом коде, мы не используем регулярные хуки useState и useEffect. Это связано с тем, что useQuery уже имеет различные значения, которые мы можем использовать внутри приложения, например, isLoading, errorresponse и return data.
Вернувшись к образцу репозитория, вы можете увидеть, как я получил список задач из API, используя ту же функцию useQuery внутри /pages/index.js:
const { status, data, error, isFetching } = useQuery('todos', async () => { const { data } = await axios.get('/api/data') return data })
Разница здесь в том, что я также использую параметр isFetching, который определяет, обрабатывает ли запрос данные или нет. Вы поймете, почему это важно. А пока давайте узнаем, как вы можете изменять удаленные данные.
Хук useMutation
Хук useMutation обычно используются для создания / обновления / удаления данных. Эта функция принимает асинхронную функцию для обновления данных (обычно между запрос POST, PUT или DELETE) и возвращает функцию mutate, которую можно вызвать, чтобы запустить мутацию.
const [mutate] = useMutation( text => axios.post('/api/data', { text }), ) mutate("Learn about React Query")
Вы также можете указать дополнительные функции, которые будут запускаться только тогда, когда функция mutate возвращает определенные результаты, например, onSuccess и onError. В образце репозитория вы можете видеть, что я использовал функцию mutate для публикации новых данных в API при отправке формы. Я также очищаю текстовое поле ввода, когда запрос Post был выполнен успешно:
const [mutatePostTodo] = useMutation( text => axios.post('/api/data', { text }), { onSuccess: () => { // Query Invalidations // queryCache.invalidateQueries('todos') setText('') }, } )
Но если вы попытаетесь вставить новый текст в демонстрационное приложение, вы увидите, что список дел не обновляется. Чтобы указать React Query обновить список задач, вам нужно раскомментировать код функции setText выше:
{ onSuccess: () => { // Query Invalidations queryCache.invalidateQueries('todos') setText('') }, }
queryCache.invalidateQueries сделает кеш недействительным с помощью ключа todo и заставит React Query снова получить данные.
Утилита queryCache
Как вы видели в демонстрации DevTools, React Query будет кэшировать полученные данные под указанным выше ключом todo, но они автоматически станут устаревшими после получения, если вы не настроите staleTime.
queryCache — это экземпляр служебной программы, содержащий множество функций, которые можно использовать для дальнейшего управления запросами. В примере вы видели, как функция queryCache.invalidateQueries используется для того, чтобы React Query отправлял новый запрос для получения списка задач. Вот полный список доступных методов queryCache.
Заключение
React Query — отличная библиотека хуков для управления запросами данных, которая полностью избавляет от необходимости помещать удаленные данные в глобальное состояние. Вам просто нужно указать библиотеке, где вы хотите получить данные, и она будет обрабатывать кеширование, фоновые обновления и аннулирование данных без какого-либо дополнительного кода или конфигурации.
React Query также устраняет необходимость использовать хуки useState и useEffect и заменяет их на несколько строк логики React Query. В конечном итоге это определенно поможет вам поддерживать приложение. Если вам интересно узнать больше, не забудьте ознакомиться с документацией по React Query.
Автор: Nathan Sebhastian
Источник: https://blog.bitsrc.io
Редакция: Команда webformyself.