DEV Community

sundaycoding
sundaycoding

Posted on

React Query: как я упростил управление серверным состоянием в React

React Query: как я упростил управление серверным состоянием в React
Обработка данных, которые приходят с сервера, может стать настоящей головной болью в React. Нужно думать о многом: обновление, кэширование, повторная загрузка... React Query здорово мне в этом помогает! Он берет на себя все эти сложности, а еще предлагает простые решения для оптимистичного рендеринга, бесконечного скролла, пагинации и многого другого.

Хочу поделиться своим опытом использования React Query и показать, как он упрощает разработку.

Установка и подготовка
Для начала, я создал новое React-приложение с помощью npx create-react-app. Затем установил React Query с помощью npm i --save react-query.

Для демонстрации я использовал Json Placeholder API, чтобы создать простой блог.

Загрузка данных
Сначала я удалил весь шаблонный код в App.js и заменил его следующим кодом:

JavaScript

import React from 'react';
import { useQuery } from 'react-query';

const getPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
return response.json();
};

function App() {
const { status, data, isFetching, error } = useQuery('posts', getPosts);

if (status === 'loading') {
return

Загрузка...; // loading state
}

if (status === 'error') {
return

Ошибка: {error.message}; // error state
}

return (


{data && (
    {data .slice(0, 10) // только первые 10 .map((d) => (
  • {d.title}
  • ))}

)}
{isFetching &&

Обновление...

}

);
}

export default App;
Сначала я определил функцию getPosts — она может включать в себя что угодно, главное, чтобы она возвращала асинхронную функцию.

Внутри компонента App я вызвал хук useQuery с идентификатором для данных ('posts') и асинхронной функцией getPosts.

Хук возвращает status, data, isFetching и error. status может быть 'success', 'loading' или 'error'. Остальная часть компонента отображает результат в трех возможных состояниях.

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

Это, в принципе, все, что вам нужно знать, чтобы начать использовать React Query. Но давайте расширим этот пример, чтобы увидеть кэширование и обновление в действии!

Расширение приложения
Сначала я перенес код из App.js в новый компонент components/Home.js. Далее я переименую компонент и добавлю NavLink в список сообщений.

JavaScript

import React from 'react';
import { NavLink } from 'react-router-dom';
import { useQuery } from 'react-query';

const getPosts = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
await new Promise((r) => setTimeout(r, 1000)); // wait a second
return response.json();
};

function Home() {
const { status, data, isFetching, error } = useQuery('posts', getPosts);

if (status === 'loading') {
return

Загрузка...; // loading state
}

if (status === 'error') {
return

Ошибка: {error.message}; // error state
}

return (


{data && (
    {data .slice(0, 10) // только первые 10 .map((d) => (
  • {d.title}
  • ))}

)}
{isFetching &&

Обновление...

}

);
}

export default Home;
Теперь добавим в App.js маршрутизатор, который сопоставляет маршруты / для Home.js и /post/:id для страницы отдельного поста.

JavaScript

import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import Post from './components/Post';

function App() {
return (



path="/post/:id"
render={(routerProps) => }
/>


);
}

export default App;
И наконец, я создал новый компонент components/Post.js для отображения данных одного поста.

JavaScript

import React from 'react';
import { NavLink } from 'react-router-dom';
import { useQuery } from 'react-query';

const Post = ({ id }) => {
const getPost = async () => {
const response = await fetch(https://jsonplaceholder.typicode.com/posts/${id});
const jsonResponse = await response.json();
jsonResponse.title = ${jsonResponse.title} - ${Math.random().toString(36)};

await new Promise((r) => setTimeout(r, 1000)); // wait a second
return jsonResponse;
Enter fullscreen mode Exit fullscreen mode

};

const { status, data, isFetching } = useQuery(post-${id}, getPost);

if (status === 'loading') {
return

Загрузка...; // loading state
}

return (


{data.title}


{data.body}


{isFetching &&

Обновление...

}


Домой

);
};

export default Post;
Здесь useQuery не сильно отличается от того, что в Home.js. Он добавляет id к идентификатору, поэтому каждое сообщение имеет свой собственный state. Кроме того, я добавил тайм-аут в 1 секунду к функции getPost, чтобы сделать состояние загрузки более заметным. Также я добавил случайную строку к заголовку, чтобы сделать повторную загрузку видимой.

И это, на самом деле, весь код, который вы видели в начале поста.

Если вы начнете работать с React Query, я бы порекомендовал вам посмотреть react-query-devtools, чтобы иметь возможность просматривать state и кэш.

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

nextjs tutorial video

Youtube Tutorial Series 📺

So you built a Next.js app, but you need a clear view of the entire operation flow to be able to identify performance bottlenecks before you launch. But how do you get started? Get the essentials on tracing for Next.js from @nikolovlazar in this video series 👀

Watch the Youtube series