React Query — залог эффективных запросов

React Query — залог эффективных запросов

KOD

Настройка проекта

Сначала необходимо инициализировать репозиторий. Для этого выполняем следующую команду в терминале:

Ввод команды в терминале для инициализации репозитория

В данном проекте применяются такие сторонние библиотеки, как:

  • React-query — для выполнения запросов fetch и post к API.
  • Formik — для создания текстовой формы, позволяющей пользователю осуществлять поиск данных по ID.

Для их установки вводим в терминал команду:

Ввод команды в терминале для установки пакетов

После этого переходим в src/App.js и удаляем код между тегами div. В итоге файл src/App.js должен выглядеть таким образом:

В App.js код должен выглядеть именно так

Получаем следующий результат:

Результат кода

Теперь переходим к выполнению простых запросов fetch с помощью React Query.

Получение и отображение данных

На первом этапе создаем файл Passenger.js в директории src. Он отвечает за получение данных с сервера. В статье используется Fake REST API.

В src/Passenger.js прописываем код:

import { useQuery } from "react-query";

function Passengers() {
  const { isLoading, error, data, isSuccess } = useQuery("passengers", () =>
    fetch(
      "https://api.instantwebtools.net/v1/passenger?page=0&size=10"
    ).then((res) => res.json())
  );
  return (
    <div>
      {isSuccess &&
        data.data.map((item) => (
          <div key={item._id}>
            <p>{item.name}</p>
            <p>{item._id}</p>
          </div>
        ))}
      {isLoading && <p>Loading..</p>}
      {error && <p>Error occurred!</p>}
    </div>
  );
}

export default Passengers;
  • Строка 1. Импортируем метод useQuery из пакета React Query, позволяющий выполнять запросы fetch.
  • Строка 4. Извлекаем поля isLoadingerrordata и isSuccess из хука useQuery. Первый параметр useQuery — это ключ, применяемый для идентификации запроса.
  • Строки 5-7. Сообщаем React о намерении выполнить запрос fetch к API, после чего преобразуем полученные данные в JSON.
  • Строка 11. Если запрос был успешным (isSuccess является true), то отображаем данные. В нашем случае ими будут поля id и nameкаждого элемента.
  • Строки 12–13. Если запрос продолжает загружаться или вернул ошибку (isLoading является true или error не является null), то показываем надлежащее сообщение.

Далее переходим в App.js и импортируем QueryClientQueryClientProvider из пакета React Query , а также компонент Passengers:

Код для App.js

Непосредственно поверх объявления компонента App пишем следующий фрагмент кода:

Код для App.js
  • Строка 1. Создаем экземпляр QueryClient для взаимодействия с кэшем.

Теперь находим данный фрагмент кода в App.js:

Код, который нужно найти в App.js

Заменяем его блоком кода, указанным ниже:

Код для замены
  • Строка 3. QueryClientProvider служит мостом между приложением и QueryClient, иначе говоря, позволяет реализовать кэширование в приложении.
  • Строка 4. Отрисовываем компонент Passengers.

Выполняем код, получая следующий результат:

Вывод кода

Как видим, код работает. Простой запрос fetch успешно выполнен с помощью React Query.

В следующем разделе узнаем, как осуществлять поиск конкретных данных посредством ID.

В итоге App.js должен выглядеть так:

import { QueryClient, QueryClientProvider } from "react-query";
import Passengers from "./Passengers";

const queryClient = new QueryClient();
function App() {
  return (
    <div>
      <QueryClientProvider client={queryClient}>
        <Passengers />
      </QueryClientProvider>
    </div>
  );
}

export default App;

Поиск по ID

В каталоге src создаем файл PassengerID.js. Компонент PassengerIDпозволит пользователю искать данные пассажира всего лишь путем ввода ID.

В src/PassengerID.js начинаем с импорта библиотек:

Код для PassengerID
  • Строка 1. Используем переменную состояния для отслеживания ID.
  • Строка 2 помогает в выполнении запросов к API.
  • Хук useFormik содействует в создании форм.

Далее пишем код в файле PassengerID:

function PassengerID() {
  const [id, setID] = useState("");
  const formik = useFormik({
    initialValues: {
      _id: "",
    },
    onSubmit: (values) => {
      console.log(JSON.stringify(values, null, 2));
      setID(values._id);
    },
  });
  const fetchPassenger = async (id) => {
    const res = await fetch(
      `https://api.instantwebtools.net/v1/passenger/${id}`
    );
    return res.json();
  };
  const { data, error, isLoading } = useQuery(["passengerID", id], () =>
    fetchPassenger(id)
  );
}

export default PassengerID;
  • Строка 2. Хук id сообщает React Query идентификатор, по которому нужно произвести запрос через API.
  • Строка 3. Хук useFormik помогает в создании формы. Здесь мы информируем Formik о том, что начальное значение текстового поля _id будет пустым.
  • Строка 7. Если пользователь отправляет форму, то вызываем функцию setID для изменения переменной id на значение, введенное им в текстовое поле.
  • Строка 12. Объявляем функцию fetchPassenger, которая выберет пользователя в соответствии с ID, присутствующим в параметре. В итоге сырые данные будут преобразованы в JSON и затем возвращены.
  • Строка 18. Запускаем функцию useQuery для выполнения запроса fetch к API. Обратите внимание на добавление в ключ переменной состояния id. Дело в том, что наш запрос зависит от переменной id. Таким образом мы даем указание React выполнять запрос при каждом изменении состояния id.
  • Строка 19. Вызываем функцию fetchPassenger и передаем параметр id.

Данные извлечены, осталось их только отобразить.

В довершении всего добавляем код в PassengerID.js:

return (
  <div>
    <h1>Find by ID</h1>
    <form onSubmit={formik.handleSubmit}>
      <input 
        id="_id" 
        name="_id"
        type="text" 
        onChange={formik.handleChange}></input>
    </form>
    {error && <p>Error!</p>}
    {data && (
      <p>
        {data.name}, {data.trips}
      </p>
    )}
    {isLoading && <p>Loading..</p>}
  </div>
);
  • Строка 4. Создаем элемент form и в случае отправки пользователем формы инструктируем React запустить соответствующий обработчик.
  • Строка 5. Создаем текстовое поле input с id=”_id" и name="_id". Необходимо отметить, что мы передаем это поле id и name, соответствующее свойству, которое было определено ранее в свойстве initialValues, расположенном в хуке useFormik.
  • Строка 12. Если данные возвращаются, то отображаем поля name и trips (поездок) пассажира.

Теперь код принял свой окончательный вид. На этом этапе необходимо отрисовать компонент PassengerID в DOM.

В App.js находим фрагмент кода:

Код, который нужно найти в App.js

Меняем его следующим образом:

Код для App.js
  • Строка 5. Отрисовываем компонент PassengerID.

Выполняем код, в результате получая:

Вывод кода

Убеждаемся в работоспособности кода. Обратите внимание, что при каждом изменении переменной состояния id, происходит повторное извлечение данных.

Тема данного раздела исчерпана, и пора переходить к следующему, в котором подробно будем знакомиться с библиотекой React Query.

Напоследок покажем, как должен выглядеть PassengerID.js:

import { useState } from "react";
import { useQuery } from "react-query";
import { useFormik } from "formik";
import Passengers from "./Passengers";

function PassengerID() {
  const [id, setID] = useState("");
  const formik = useFormik({
    initialValues: {
      _id: "",
    },
    onSubmit: (values) => {
      console.log(JSON.stringify(values, null, 2));
      setID(values._id);
    },
  });
  const fetchPassenger = async (id) => {
    const res = await fetch(
      `https://api.instantwebtools.net/v1/passenger/${id}`
    );
    return res.json();
  };
  const { data, error, isLoading } = useQuery(["passengerID", id], () =>
    fetchPassenger(id)
  );
  return (
    <div>
      <h1>Find by ID</h1>
      <form onSubmit={formik.handleSubmit}>
        <input
          id="_id"
          name="_id"
          type="text"
          onChange={formik.handleChange}
        ></input>
      </form>
      {error && <p>Error!</p>}
      {data && (
        <p>
          {data.name}, {data.trips}
        </p>
      )}
      {isLoading && <p>Loading..</p>}
    </div>
  );
}

export default PassengerID;

React Query: дополнительные возможности

В этом разделе рассмотрим:

  • пагинацию;
  • мутации.

Начнем с пагинации.

Пагинация

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

В файле Passengers.js объявляем переменную состояния page:

Код для Passengers.js

Это позволит отслеживать текущую страницу.

Далее пишем такой фрагмент кода:

Код для Passengers.js

В этой функции мы инструктируем React извлечь записи через API с указанной страницы. В итоге возвращаются преобразованные данные JSON.

Далее находим следующий фрагмент кода:

Код, который нужно найти в Passengers.js

Теперь меняем его таким образом:

Код для Passengers.js
  • Строка 2. Сообщаем React, что запрос зависит от переменной page. При изменении состояния page выполняем запрос заново.
  • Строка 3. Извлекаем данные пассажира с помощью переменной page в качестве параметра.
  • Строка 4. keepPreviousData дает указание React сохранять старые данные при изменении ключа запроса.

Мы почти у цели. Далее находим блок return в Passengers.js:

Код, который нужно найти в Passengers.js

Добавляем следующие строки кода сразу после открывающего тега div:

Код для Passengers.js
  • Строка 3. Инструктируем React уменьшить состояние page и остановить его при достижении 0.
  • Строка 4. Увеличиваем состояние page.
  • Строка 5. Отображаем значение page.

Вот теперь закончили! Выполняем код, в результате получая:

Вывод кода

Как видим, код работает. Теперь займемся мутациями.

Окончательный вариант кода Passengers.js:

import { useState } from "react";
import { useQuery } from "react-query";

function Passengers() {
  const [page, setPage] = useState(0);

  const fetchPassengers = async (page) => {
    const res = await fetch(
      `https://api.instantwebtools.net/v1/passenger?page=${page}&size=10`
    );
    return res.json();
  };

  const { isLoading, error, data, isSuccess } = useQuery(
    ["passengers", page],
    () => fetchPassengers(page),
    { keepPreviousData: false }
  );
  return (
    <div>
      <button onClick={() => setPage((old) => Math.max(0, old - 1))}>
        {" "}
        -{" "}
      </button>
      <button onClick={() => setPage((old) => old + 1)}> + </button>

      <p> {page} </p>
      {isSuccess &&
        data.data.map((item) => (
          <div key={item._id}>
            <p>{item.name}</p>
            <p>{item._id}</p>
          </div>
        ))}
      {isLoading && <p>Loading..</p>}
      {error && <p>Error occurred!</p>}
    </div>
  );
}

export default Passengers;

Мутации

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

Здесь в дело вступают мутации, позволяющие выполнять запросы POSTи PUT.

Но прежде установим axios для осуществления вышеуказанных запросов к API.

Ввод команды в терминал для установки axios

В директории src создаем файл AddPassenger.js. Начинаем с импорта модулей:

Код для AddPassenger.js
  • Строка 1. Объявляем переменные состояния для последующей их отправки к API в качестве данных.
  • Строка 2. Хук useMutation инструктирует React изменить данные на сервере.
  • Строка 3. Axios разрешает выполнить запросы POST к API.
  • Строка 4 способствует извлечению данных из формы.
function AddPassenger() {
  const formik = useFormik({
    initialValues: {
      name: "",
      trips: 0,
      airline: 1,
    },
    onSubmit: (values) => {
      console.log(JSON.stringify(values, null, 2));
      mutation.mutate({
        name: values.name,
        trips: values.trips,
        airline: values.airline,
      });
    },
  });
}
export default AddPassenger;
  • Строки 2–6. Создаем хук useFormik, имеющий 3 значения nametripsи airline.
  • Строки 8–16. При отправке пользователем формы выполняем мутацию. Отправляем значения текстовых полей в качестве данных на сервер. В дальнейшем определяем mutation.

Затем пишем фрагмент код:

const mutation = useMutation((item) =>
  axios.post("https://api.instantwebtools.net/v1/passenger/", item)
);
if (mutation.isSuccess) console.log(mutation.data.data);
  • Строка 1. Создаем экземпляр useMutation.
  • Строка 2. Выполняем запрос POST к API. Переменная item является телом данных, которые будут отправлены позже.
  • Строка 4. Если мутация была успешной (свойство isSuccessявляется true), то регистрируем возвращаемые данные в консоли.

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

Пишем следующий код в файле AddPassenger.js:

return (
    <div>
      <h1>Submit form</h1>
      <form onSubmit={formik.handleSubmit}>
        <label>
          Name
          <input id="name" type="text" onChange={formik.handleChange} />
        </label>
        <label>
          Trips
          <input id="trips" type="number" onChange={formik.handleChange} />
        </label>
        <label>
          Airline:
          <input id="airline" type="number" onChange={formik.handleChange} />
        </label>
        <button type="submit">Submit</button>
      </form>
      {mutation.isLoading && <p>Please wait</p>}
      {mutation.isSuccess && <p>Success! ID: {mutation.data.data._id}</p>}
    </div>
  );
  • Строка 4. Запускаем обработчик отправки Formik, когда пользователь отправляет форму.
  • Строки 7–15. Создаем несколько текстовых полей для nametrips и airline.
  • Строка 19. Если запрос загружается (свойство isLoading является true), то отображаем надлежащее сообщение.
  • Строка 20. В случае успешного выполнения мутации (свойство isSuccess является true) отображаем ID нового пассажира.

Работа над этим кодом завершена, осталось отобразить компонент AddPassenger в DOM.

Переходим к src/App.js и находим блок кода:

Код, который нужно найти в App.js

Меняем его таким образом:

Замена кода в App.js
  • Строка 4. Отображаем компонент AddPassenger.

Выполняем код и получаем результат:

Вывод кода

Код работает. Мы получили ID пассажира. Попробуем его найти.

Поиск по ID

Все прекрасно функционирует!

Заключение

Вот такая неимоверно легкая в применении React Query. Нам не пришлось писать много кода для добавления поддержки пагинации или выполнения запроса POST. Неудивительно, что крупные корпорации, например Microsoft и eBay, используют для продакшена именно React Query.

Report Page