React Query и React Table - две невероятно модные библиотеки, дополняющие React Development. React Query обеспечивает самоуверенный подход к синхронизации данных, а React Table упрощает самые раздражающие части модернизации HTML-таблиц.

В этом посте я продемонстрирую, как вы можете объединить их вместе. В этом посте предполагается, что вы уже в некоторой степени знакомы с react-query и react-table, но в случае, если вы не знаете, я сначала рассмотрю некоторые ключевые идеи из обеих библиотек. Из-за того, насколько сложными могут быть React Query и React Table, я настоятельно рекомендую сначала прочитать их начальную документацию.

Мы будем следовать примеру кода, который можно найти на github.com/nafeu/react-query-table-sandbox. Вы можете настроить это так:

git clone https://github.com/nafeu/react-query-table-sandbox.git
cd react-query-table-sandbox
npm install
npm start

В основном мы сосредоточимся на файле ReactQueryWithTable.jsx. Давайте начнем.

React Query - ключевые идеи

Одна из основных частей React Query - ловушка useQuery. В компоненте TableQuery из ReactQueryWithTable.jsx у нас есть следующее:

const {
  data: apiResponse,
  isLoading
} = useQuery('discussionGroups', fetchData);

Это можно разбить следующим образом:

  • discussionGroups - это ключ, который мы используем для однозначной идентификации запроса в зависимости от его контекста. В данном случае это HTTP-запрос к REST API. Это необходимо для различения и изоляции нескольких запросов, которые работают с одним объектом QueryClient и его кешем.
  • fetchData - это вспомогательная функция, которая выполняет запрос API и возвращает обещание. Мы можем определить это любым удобным способом, в этом коде мы используем axios.
  • data - это объект ответа, который мы получаем от нашего API, который мы деструктурируем и переименовываем в apiResponse
  • isLoading - это переменная состояния загрузки, которую мы можем использовать для информирования нашего пользовательского интерфейса.

По сути, использование этого хука позволяет нам подключать нашу логику запроса API (с некоторыми встроенными конфигурациями повторной выборки, кеширования и опроса по умолчанию), извлекать наши данные и использовать полезные переменные состояния загрузки для создания нашего пользовательского интерфейса в удобной для чтения и предсказуемой форме. .

Таблица React - Ключевые идеи

Одной из основных частей React Table также является хук, и это хук useTable. Мы запоминаем и загружаем данные таблицы в useTable. Затем ловушка возвращает множество помощников, которые отвечают за улучшение нашей таблицы HTML по умолчанию. Усовершенствования позволяют нам легко отображать данные наших таблиц, а также реализовывать сортировку, фильтрацию, разбиение на страницы и многое другое. Давайте посмотрим на компонент TableLayout из ReactQueryWithTable.jsx:

Сначала это может показаться пугающим, но после того, как вы поймете, как поток props из React Table в наш компонент, это не так уж плохо. Его можно разбить следующим образом:

  • getTableProps извлекает набор свойств, необходимых для того, чтобы таблица могла использовать функции библиотеки.
  • getTableBodyProps похож на getTableProps, но для тега tbody
  • headerGroups (содержащий собственные вспомогательные функции getHeaderGroupProps и getHeaderProps) отвечает за все функции библиотеки, связанные с тегами thead и tr.
  • rows - отдельные строки, которые будут отображаться с помощью связанных с ними похожих вспомогательных методов.
  • prepareRow позволяет нам лениво подготовить строку к рендерингу

Проще говоря, мы используем эти помощники, возвращенные нам из хука useTable, чтобы внедрить все правильные реквизиты в наш тег <table> и при этом использовать все невероятные возможности React Table.

Понимание наших фиктивных данных

В примере кода я подготовил фиктивный api, который возвращает данные для воображаемого веб-сайта группы обсуждения разработчиков программного обеспечения. Данные отформатированы так:

Что должно сгенерировать таблицу в нашем пользовательском интерфейсе следующим образом:

Самое интересное в нашем псевдониме API - это то, что он динамический. Каждый раз, когда вы отправляете запрос api на localhost:8000/api, он отправляет обновленную полезную нагрузку. Это предназначено для моделирования реального сценария, когда люди активно публикуют сообщения в группах обсуждения, открывают новые темы и решают проблемы. Это также поможет нам увидеть, как React Query обрабатывает динамические изменения в нашей таблице без какой-либо дополнительной настройки.

В нашем ReactQueryWithTable.jsx файле мы определяем функцию fetchData, которая отправляет запросы к этому API следующим образом:

const fetchData = () => axios.get(`http://localhost:8000/api`);

Предложение по структурированию запроса React с таблицей React

ReactQueryWithTable.jsx состоит из трех основных компонентов:

  1. TableQuery, который обращается к QueryClient из React Query и обрабатывает нашу логику синхронизации данных.
  2. TableInstance, который запоминает данные нашей таблицы и использует ловушку useTable из React Table.
  3. TableLayout, который берет всех помощников, предоставленных нам ловушкой useTable, связывает их с необходимым JSX (разметкой) и отображает нашу итоговую таблицу.

Это разделение работает последовательно:

TableQuery
  -> handles query logic (React Query)
  -> prepares table data as a prop
  -> returns TableInstance

TableInstance
  -> memoizes data
  -> initiates table instance (React Table)
  -> prepares table instance props
  -> returns TableLayout

TableLayout
  -> utilizes table instance helpers (passed as props)
  -> injects props into elements
  -> renders table

Компонент TableQuery

Сначала мы подключаемся к нашему queryClient с помощью хука useQueryClient. Затем мы объявляем переменную состояния tableData и связанный с ней установщик с помощью ловушки useState. Это подготавливает почву для дальнейшей работы с данными таблицы, полученными нашим api. Затем мы используем хук useQuery, как объяснялось ранее, и делаем следующее:

useEffect(() => {
  setTableData(apiResponse?.data);
}, [apiResponse])

Это установит для нашего tableData соответствующий ответ API, как только он будет получен в useQuery.

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

Теперь, когда мы заполнили наш tableData, мы передаем его как опору следующему компоненту в нашей последовательности, компоненту TableInstance.

Компонент TableInstance

Имея доступ к нашему tableData, мы создаем и деструктурируем в массиве две новые переменные с именами columns и data. Они отвечают за определение столбцов нашей таблицы и за то, как они получают доступ к связанным с ними данным.

Столбцы можно отформатировать как коллекцию (или вложенную коллекцию), где мы используем Header в качестве метки для заголовка таблицы и accessor, чтобы указать React Table, для какого ключа выбрать правильное значение из data.

Наша переменная data также структурирована как коллекция (массив объектов) и содержит необработанные данные таблицы, возвращенные нашим API.

Затем мы используем columns и data для создания экземпляра tableInstance с помощью хука useTable:

const tableInstance = useTable({ columns, data });

Он содержит все помощники, необходимые для улучшения нашей утомительной старой обычной таблицы HTML. Он также содержит наш tableData, но отформатирован таким образом, чтобы React Table мог понимать и работать с ним. Затем мы распространяем все свойства tableInstance в качестве опор на компонент TableLayout и продвигаемся оттуда.

Компонент TableLayout был фактически одной из первых вещей, которые мы объяснили в этом посте. Как видите, разбив наши компоненты на query layer, data processing layer и render layer, мы можем эффективно подготовить данные нашей таблицы для отображения.

Результат

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

Удачного кодирования!