Интеграция React и DataTables — не так тяжело, как рекламируют

в 14:30, , рубрики: ReactJS, вискас, Разработка веб-сайтов

Несколько месяцев назад я искал React-компонент для отображения таблицы данных в одном из наших веб-приложений в Undertone. В предыдущем проекте, который не был основан на высокоуровневой библиотеке, такой как React, мы использовали jQuery-плагин DataTables, и мы были очень довольны той гибкостью, которую он предлагает. Теперь я искал нечто похожее, которое можно легко интегрировать как React-компонент в наше новое приложение.

Проведя довольно обширные исследования, я узнал две вещи. Во-первых, это то, что не рекомендуется использовать DataTables вместе с React, потому что обе библиотеки управляют DOM. Во-вторых, не было библиотеки, которая обеспечивала гибкость, необходимую для нашего веб-приложения (с момента моего исследования). Крайний срок для сдачи проекта приближался, и мне нужно было что-то выбрать. Я решил пойти по непопулярному пути и интегрировать DataTables в свой проект. Результат получился намного лучше, чем я ожидал, и весь процесс интеграции на самом деле был довольно плавным. В следующих разделах я опишу схему проекта, в котором работает интеграция React + DataTables.

Предварительная установка

Мы будем использовать Create-React-App (CRA) для строительных лесов нашего проекта. Если вы не знакомы с CRA, это в основном инструмент для создания приложений React без конфигурации. Первое, что нам нужно сделать, это установить CRA (если вы его еще не установили) и инициализировать новый проект с помощью команды create-react-app (см. документацию по CRA для получения подробных сведений о том, как инициализировать и запустить проект).

Мы завершаем нашу установку, добавляя модули jQuery и Datatables в качестве dev-dependencies.

$ npm i --save-dev datatables.net jquery 

После завершения установки модулей мы удаляем ненужные файлы, автоматически генерируемые CRA из репозитория. Окончательный результат проекта, который мы создаем здесь в этой статье, можно найти в репозитории react-datatables на GitHub.

Простой UI

Мы реализуем очень простой интерфейс. У пользователей есть область ввода, где они могут вводить имя и псевдоним в соответствующие текстовые поля. Когда нажимается кнопка «Добавить», данные, введенные в текстовые поля, добавляются в таблицу данных. Имя является уникальным «ключом» для каждой записи — если пользователь набирает имя, которое уже существует, новая пара имен-ников не создается, и только псевдоним существующей пары обновляется в таблице.

Интеграция React и DataTables — не так тяжело, как рекламируют - 1

 

Настройка DataTables

У нас уже есть исходные файлы с пустым контентом, созданным CRA. Мы создаем новый файл, содержащий наш компонент Table — этот компонент отвечает за визуализацию и управление таблицей. Сначала мы импортируем как jQuery, так и DataTables и связываем их так, чтобы DataTables имел доступ к функциям jQuerey. Это можно сделать с помощью следующих двух строк:

const $ = require('jquery');
$.DataTable = require('datatables.net');

Мы определяем два столбца, которые извлекают соответствующие значения из пары имя-ник, которую мы собираемся предоставить таблице:

const columns = [
  {
    title: 'Name',
    width: 120,
    data: 'name'
  },
  {
    title: 'Nickname',
    width: 180,
    data: 'nickname'
  },
];

Наконец, само определение компонента:

class Table extends Component {
  componentDidMount() {
    $(this.refs.main).DataTable({
      dom: '<"data-table-wrapper"t>',
      data: this.props.names,
      columns,
      ordering: false,
    })
  }

  componentWillUnmount() {
    $('.data-table-wrapper')
      .find('table')
      .DataTable()
      .destroy(true)
  }

  shouldComponentUpdate(nextProps) {
    if (nextProps.names.length !== this.props.names.length) {
      reloadTableData(nextProps.names)
    } else {
      updateTable(nextProps.names)
    }
    return false
  }

  render() {
    return (
      <div>
        <table ref="main" />
      </div>
    )
  }
}

Несколько замечаний. В функции render мы создаем один HTML-элемент таблицы. Это требование DataTables, поскольку для заполнения DOM нужен элемент таблицы. React никогда не узнает, что внутри элемента таблицы будет больше DOM. Мы гарантируем, что никаких повторных попыток со стороны React не произойдет, всегда возвращая false из метода shouldComponentUpdate. Сама инициализация таблицы должна произойти только один раз, когда наш компонент монтируется, потому что мы хотим оставить все внутренние манипуляции DOM в DataTables. Наконец, нам нужно уничтожить таблицу, когда компонент должен быть размонтирован. Это делается в методе componentWillUnmount с соответствующим вызовом API DataTables.

В настоящее время наш компонент Table берет свои данные через props.names, но мы не реализовали способ добавления или обновления имен. Мы сделаем это в следующем разделе.

Обновление таблицы

Существует два способа изменения массива пар имя-ник. Во-первых, добавив на него новую пару имя-ник. Во-вторых, заменив существующую пару имя-ник новой парой с таким же именем и другим ником. Это делается в другом компоненте, внешнем по отношению к компоненту Table. (Я не буду вдаваться в подробности о том, как распространяются эти обновления — более подробную информацию см. в репозитории проекта на GitHub.) Здесь мы рассмотрим два типа обновлений с помощью двух разных методов.

1) Когда добавляется новая пара имя-ник, мы перезагружаем всю таблицу:

function reloadTableData(names) {
  const table = $('.data-table-wrapper').find('table').DataTable()
  table.clear()
  table.rows.add(names)
  table.draw()
}

Мы используем стандартный селектор jQuery, чтобы найти экземпляр таблицы, используя класс, который мы предоставили в componentDidMount (data-table-wrapper). Затем мы удаляем все предыдущие данные и загружаем новые данные (для краткости я не добавлял новую пару имя-ник — это также работает, если вы удаляете одну пару или несколько пар).

2) Когда пара обновляется, мы хотим найти эту пару и изменить конкретную часть данных, которые были изменены (поле ника в нашем примере):

function updateTable(names) {
  const table = $('.data-table-wrapper').find('table').DataTable()
  let dataChanged = false
  table.rows().every(function() {
    const oldNameData = this.data()
    const newNameData = names.find(nameData => {
      return nameData.name === oldNameData.name
    })
    if (oldNameData.nickname !== newNameData.nickname) {
      dataChanged = true
      this.data(newNameData)
    }
    return true
  })

  if (dataChanged) {
    table.draw()
  }
}

Мы должны не забыть перерисовывать таблицу с помощью API-метода draw, если какие-либо данные были изменены или изменения не будут видны пользователю.

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

  shouldComponentUpdate(nextProps) {
    if (nextProps.names.length !== this.props.names.length) {
      reloadTableData(nextProps.names)
    } else {
      updateTable(nextProps.names)
    }
    return false
  }

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

Вывод

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

PS

Пожалуйста, поделитесь опытом — какие используете React-компоненты для реализации функционала таблиц с сортировкой и пагинацией для манипуляции большими объемами данных?

Автор: comerc

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js