Ниже приведен простой случай получения данных с сервера.
function App() {
const [data, updateData] = useState(null);
const [isError, setError] = useState(false);
const [isLoading, setLoading] = useState(false);
useEffect(async () => {
setError(false);
setLoading(true);
try {
const data = await axios.get('/api/user');
updateData(data);
} catch(e) {
setError(true);
}
setLoading(false);
}, [])
}
При написании компонентов с помощью React Hooks нам часто приходится вручную поддерживать состояние обработки с сервера. Вызывает некоторые проблемы в повседневном развитии. При работе с асинхронными данными нам нужно учитывать множество вещей, таких как обновление, кэширование или повторная выборка. Использование React-Query может помочь вам более эффективно управлять состоянием на стороне сервера.
Что такое React-запрос
Это библиотека запросов для React Hooks. Эта библиотека поможет вам получать, синхронизировать, обновлять и кэшировать ваши удаленные данные. Она предоставляет два простых хука для выполнения таких операций, как добавление, удаление, изменение и запрос. React-Query использует декларативное управление состоянием сервера и может использовать нулевую настройку из поле используется для обработки кэширования, фоновых обновлений и устаревших данных. Никакой громоздкой конфигурации, напишите useReduce и поддерживайте глобальное состояние, просто знайте, как использовать Promise или async/await, передать функцию, которая может анализировать данные (или вызвать ошибку), и оставить все остальное React-Query, используя меньше кода для более высокой эффективности.
Начать работу с React-Query
Установить React-запрос
$ npm i react-query
# or
$ yarn add react-query
Давайте перепишем его с помощью React-Query
import { useQuery } from 'react-query'
function App() {
const {data, isLoading, isError} = useQuery('userData', () => axios.get('/api/user'));
if (isLoading) {
return <div>loading</div>;
}
return (
<ul>
{data.map(user => <li key={user.id}>{user.name}</li>)}
</ul>
)
}
Строка «userData» в примере является уникальным ключом для этого запроса. Как видите, React-Query инкапсулирует полное промежуточное состояние запроса (isLoading, isError...). Мало того, React-Query также делает за нас следующую работу:
- Выдается только один запрос, когда несколько компонентов запрашивают один и тот же запрос
- Стратегия аннулирования/обновления данных кеша (определение того, что кеш подходит для аннулирования, и автоматический запрос данных после аннулирования)
- Очистить мусор от устаревших данных
Три важных знания в React-Query
Общая конфигурация параметров
- staleTime Интервал времени для повторной выборки данных, по умолчанию 0
- Cache Cache Cache Time По умолчанию 1000 60 5 5 минут
- Повторите попытку повторной попытки по умолчанию 3 раза
- refetchOnWindowFocus Обновлять данные, когда окно восстанавливает фокус. По умолчанию false.
- refetchOnReconnect повторное подключение к сети
- Перемонтировать экземпляр refetchOnMount
- Если включено значение «false», «useQuery» не будет запущен, и для запуска операции необходимо использовать возвращаемый им «refetch».
Как настроить глобально? следующим образом:
import { ReactQueryConfigProvider, ReactQueryProviderConfig } from 'react-query';
const queryConfig: ReactQueryProviderConfig = {
/**
* refetchOnWindowFocus 窗口获得焦点时重新获取数据
* staleTime 过多久重新获取服务端数据
* cacheTime 数据缓存时间 默认是 5 * 60 * 1000 5分钟
*/
queries: {
refetchOnWindowFocus: true,
staleTime: 5 * 60 * 1000,
retry: 0
},
};
ReactDOM.render(
<ReactQueryConfigProvider config={queryConfig}>
<App />
</ReactQueryConfigProvider>
document.getElementById('root')
);
也可以单独配置,如下:
function Todos() {
// 第三个参数即可传参了
// "enabled"参数为false的化,不会自动发起请求,而是需要调用“refetch”来触发
const {
isIdle,
isLoading,
isError,
data,
error,
refetch,
isFetching,
} = useQuery('todos', fetchTodoList, {
enabled: false,
})
return (
<>
<button onClick={() => refetch()}>Fetch Todos</button>
{isIdle ? (
'Not ready...'
) : isLoading ? (
<span>Loading...</span>
) : isError ? (
<span>Error: {error.message}</span>
) : (
<>
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
<div>{isFetching ? 'Fetching...' : null}</div>
</>
)}
</>
)
}
Запрос данных и работа
useQuery (проверить) запросить данные (получить)
Основное использование
function Todos() {
// useQuery的第一个参数,作为useQuery查询的唯一标识,该值唯一
// 可以是string、array、object
// string -> useQuery('todos', ...) queryKey === ['todos']
// array -> useQuery(['todo', 5], ...) queryKey === ['todo', 5]
// object -> useQuery(['todo', 5, { preview: true }], ...) queryKey === ['todo', 5, { preview: true }]
const { isLoading, isError, data, error } = useQuery('todos', fetchTodoList)
if (isLoading) {
return <span>Loading...</span>
}
if (isError) {
return <span>Error: {error.message}</span>
}
// also status === 'success', but "else" logic works, too
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
)
}
передать параметры
function Todos({ completed }) {
// useQuery(['todo', { status: 1, page: 1 }], ...) queryKey === ['todo', { status: 1, page: 1 }]
// 传递参数给“fetchTodoList”使用
const queryInfo = useQuery(['todos', { status: 1, page: 1 }], fetchTodoList)
}
// 函数参数
// key -> “todos”
// status -> 1 page -> 1
function fetchTodoList(key, { status, page }) {
return new Promise()
// ...
}
Библиотека также реализует часто используемые операции запросов:
useMutation (добавить, изменить, удалить) данные операции (Post, Delete, Patch, Put
// 当“mutate()”被调用时,执行“pingMutation”
const PingPong = () => {
const [mutate, { status, data, error }] = useMutation(pingMutation)
const onPing = async () => {
try {
const data = await mutate()
console.log(data)
} catch {
}
}
return <button onClick={onPing}>Ping</button>
}
передать параметры
// "mutate({title})"就会将参数“title”传递给“createTodo”函数了
const createTodo = ({ title }) => {
console.log("title ", title)
}
const CreateTodo = () => {
const [title, setTitle] = useState('')
const [mutate] = useMutation(createTodo)
const onCreateTodo = async e => {
e.preventDefault()
try {
await mutate({ title })
// Todo was successfully created
} catch (error) {
// Uh oh, something went wrong
}
}
return (
<form onSubmit={onCreateTodo}>
<input
type="text"
value={title}
onChange={e => setTitle(e.target.value)}
/>
<br />
<button type="submit">Create Todo</button>
</form>
)
}
очистить кэш
Всякий раз, когда мы заканчиваем редактирование статьи и возвращаемся на страницу со списком, если мы не очищаем кеш, данные все еще остаются в кеше, поэтому нам нужно очистить кеш, чтобы сделать «userQuery» недействительным, и повторно получить последние данные, когда мы возвращаемся на страницу списка
Код ссылки выглядит следующим образом
import { useMutation, useQueryCache } from 'react-query'
const queryCache = useQueryCache()
const [mutate] = useMutation(addTodo, {
onSuccess: () => {
// invalidateQueries 的匹配规则
// eg:
// queryCache.invalidateQueries('todos') 那么如下两个`query key`都会被匹配到,匹配到的缓存都会失效
// const todoListQuery = useQuery('todos', fetchTodoList)
// const todoListQuery = useQuery(['todos', { page: 1 }], fetchTodoList)
queryCache.invalidateQueries('todos')
queryCache.invalidateQueries('reminders')
},
})
Devtools, поддерживающие инструменты разработки
Импорт инструментов разработки
import { ReactQueryDevtools } from 'react-query/devtools'
По умолчанию Devtools включен, когда process.env.NODE ENV === 'production' , не беспокойтесь об их исключении при сборке.
При включении в плавающем режиме он установит инструменты разработки как фиксированный плавающий элемент в разработанном приложении и предоставит кнопку-переключатель в углу экрана для отображения и скрытия инструментов разработки.
По возможности добавляйте следующий код в свое приложение React. Чем ближе к корню страницы, тем лучше!
import { ReactQueryDevtools } from 'react-query/devtools'
function App() {
return (
<QueryClientProvider client={queryClient}>
{/* The rest of your application */}
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
)
}
Экология вокруг React-Query
Окружающая среда React-Query отвечает ежедневным потребностям разработки и поддерживает TypeScript и GraphQL. Его можно использовать в React Native, а также он совместим со схемами рендеринга на стороне сервера.SSR поддерживает использование Next.js.
Сравнение других планов
- react-query может использовать хуки для мутации, поддерживает больше параметров (например, keepPreviousData), имеет больше функций и больше подходит для проектов со сложными API.
- swr относительно легкий и может использоваться где угодно без установки Provider в родительском компоненте. легче
Сравнительная таблица схем, связанных с официальным сайтом
React Query | SWR (Website) | Apollo Client (Website) | RTK-Query (Website) | |
---|---|---|---|---|
Github Repo / Stars | 18K | 16K | 16K | 372 |
Platform Requirements | React | React | React, GraphQL | Redux |
Their Comparison | (none) | (none) | Comparison | |
Supported Query Syntax | Promise, REST, GraphQL | Promise, REST, GraphQL | GraphQL | Promise, REST, GraphQL |
Supported Frameworks | React | React | React + Others | Any |
Supported Query Keys | JSON | JSON | GraphQL Query | JSON |
Query Key Change Detection | Deep Compare (Stable Serialization) | Referential Equality (===) | Deep Compare (Unstable Serialization) | Referential Equality (===) |
Query Data Memoization Level | Query + Structural Sharing | Query | Query + Entity + Structural Sharing | Query |
Bundle Size | 11.2KB | 5.0KB | 33.9KB | 10.3KB |
API Definition | On-Use, Declarative | On-Use | GraphQL Schema | Declarative |
Queries | ✅ | ✅ | ✅ | ✅ |
Caching | ✅ | ✅ | ✅ | ✅ |
Devtools | ✅ | 🟡 | ✅ | ✅ |
Polling/Intervals | ✅ | ✅ | ✅ | ✅ |
Parallel Queries | ✅ | ✅ | ✅ | ✅ |
Dependent Queries | ✅ | ✅ | ✅ | ✅ |
Paginated Queries | ✅ | ✅ | ✅ | ✅ |
Infinite Queries | ✅ | ✅ | ✅ | 🛑 |
Bi-directional Infinite Queries | ✅ | 🔶 | 🔶 | 🛑 |
Infinite Query Refetching | ✅ | ✅ | 🛑 | 🛑 |
Lagged Query Data1 | ✅ | 🛑 | 🛑 | ✅ |
Selectors | ✅ | 🛑 | ✅ | ✅ |
Initial Data | ✅ | ✅ | ✅ | ✅ |
Scroll Recovery | ✅ | ✅ | ✅ | ✅ |
Cache Manipulation | ✅ | ✅ | ✅ | ✅ |
Outdated Query Dismissal | ✅ | ✅ | ✅ | ✅ |
Render Optimization2 | ✅ | 🛑 | 🛑 | ✅ |
Auto Garbage Collection | ✅ | 🛑 | 🛑 | ✅ |
Mutation Hooks | ✅ | 🟡 | ✅ | ✅ |
Offline Mutation Support | ✅ | 🛑 | 🟡 | 🛑 |
Prefetching APIs | ✅ | 🔶 | ✅ | ✅ |
Query Cancellation | ✅ | 🛑 | 🛑 | 🛑 |
Partial Query Matching3 | ✅ | 🛑 | 🛑 | ✅ |
Stale While Revalidate | ✅ | ✅ | 🛑 | ✅ |
Stale Time Configuration | ✅ | 🛑 | 🛑 | 🛑 |
Pre-usage Query/Mutation Configuration4 | ✅ | 🛑 | 🛑 | ✅ |
Window Focus Refetching | ✅ | ✅ | 🛑 | 🛑 |
Network Status Refetching | ✅ | ✅ | ✅ | 🛑 |
General Cache Dehydration/Rehydration | ✅ | 🛑 | ✅ | ✅ |
Offline Caching | ✅ (Экспериментальный) | 🛑 | ✅ | 🔶 |
React Suspense (Experimental) | ✅ | ✅ | 🛑 | 🛑 |
Abstracted/Agnostic Core | ✅ | 🛑 | ✅ | ✅ |
Automatic Refetch after Mutation5 | 🔶 | 🔶 | ✅ | ✅ |
Normalized Caching6 | 🛑 | 🛑 | ✅ | 🛑 |
Суммировать
Использование React-Query может более эффективно управлять состоянием запроса с сервера, реализовывать более сложные требования с меньшим количеством кода и делать управление состоянием более элегантным.
Ссылка на ссылку:
Решите половину своих проблем управления состоянием с помощью реагирующего запроса