Таблицы данных в React: изменение состояния VS обновление DOM вручную; data- * атрибуты VS анонимные функции

У меня есть компонент React, который отображает таблицу слов и их переводы на основе данных, полученных с сервера. Слова делятся на группы, одно и то же слово может присутствовать более чем в одной группе. Каждая группа представлена ​​отдельным тегом <tbody> в одной таблице.

У меня есть следующий маршрут REST API для удаления слова из группы: DELETE /api/groups/group_id/words/word_id. Я хочу добавить эту функциональность в свою таблицу React, чтобы каждая строка таблицы имела кнопку удаления, которая при нажатии отправляет запрос AJAX на сервер и в случае успеха удаляет строку из таблицы.

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

this.setState(state => {
  const groups = [...state.groups];
  const groupIndex = groups.findIndex(group => group._id == group_id);
  const group = groups[groupIndex] = { ...groups[groupIndex] }; // for the sake of immutability
  const words = group.words = [...group.words];
  const wordIndex = words.findIndex(word => word._id == word_id);
  words.splice(wordIndex, 1);
  return { groups };
});

Это, в свою очередь, приведет к повторному рендерингу компонента. Но здесь возникает проблема: повторный рендеринг всего компонента только для удаления одной строки таблицы может быть излишним, поскольку this.state.groups и вложенные массивы слов придется пересекать снова (поскольку метод render() вызывает метод массивов map() для построения дерево компонентов), и после этого необходимо будет вызвать согласование React. Это кажется ужасной идеей, если мы заботимся о производительности.

Я знаю, что должен избегать этого в React, насколько это возможно, но не лучше ли в данном конкретном случае вернуться к старой доброй DOM ради производительности? Вот что я имею в виду:

deleteWord = (event, group_id, word_id) => {
  fetch(`/api/groups/${group_id}/words/${word_id}`, {
    method: 'DELETE'
  }).then(response => {
    if (!response.ok) throw new Error(response.statusText);
  }).then(() => {
    // event.target is the delete button that has been clicked
    const td = event.target.parentNode; // table cell
    const tr = td.parentNode; // table row
    tr.parentNode.removeChild(tr);
  });
};

Я все еще мог обновлять состояние, чтобы все было синхронизировано, но с shouldComponentUpdate(), возвращающим false, чтобы избежать ненужных вычислений.

Итак, мой первый вопрос: какой путь мне выбрать? Может я ошибаюсь и разница в производительности не так критична?

Однако это не единственный вопрос, который у меня есть. Я еще ничего не сказал о том, как я собираюсь получить значения group_id и word_id при нажатии одной из кнопок удаления. И именно здесь у меня возникает другая дилемма.

Наиболее очевидный подход - добавить анонимные функции в качестве прослушивателей событий при рендеринге:

const tables = this.state.groups.map(group => {
  const rows = group.words.map(({ _id, word, translations }) => (
    <tr key = {_id}>
      <td>{word}</td>
      <td>{translations.join(', ')}</td>
      <td><a href = "#" onClick = {event => {
        this.deleteWord(event, group._id, _id)
      }}>Delete</a></td>
    </tr>
  ));

  return <tbody key = {group._id}>{rows}</tbody>;
});

return <table>{tables}</table>;

Но я думаю, мне следует избегать этого, чтобы не создавать эти функции снова, если компонент когда-либо потребуется повторно отрисовать. Итак, другой вариант, о котором я думал, - это добавить атрибуты HTML5 data- * для хранения group_id и word_id, а затем получить к ним доступ через объект event. Я хотел бы знать, действительно ли это лучшая идея, и это мой второй вопрос.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
267
1

Ответы 1

Вы можете использовать мемоизацию при передаче объектов, массивов и функций компонентам, чтобы предотвратить их повторную визуализацию, если они не изменились. Несмотря на то, что таблица в целом изменилась, отдельные строки не изменились, поэтому нет причин повторно отображать каждую строку. Повторная визуализация таблицы не должна вызывать повторную визуализацию строк, если вы отделяете свои строки от компонента таблицы и / или предоставляете им соответствующие key.

Вы можете использовать key для ссылки на элементы в сопоставленном массиве, чтобы предотвратить их повторную визуализацию, когда в них ничего не изменилось. Когда таблица повторно отрисовывается, она увидит, что строка с ключом «value1» не изменилась, и, таким образом, не будет повторно отрисовывать эту строку. Он увидит, что строка с ключом "value2" отсутствует, и таким образом удалит ее из DOM. Он увидит, что строка с ключом «value3» не изменилась, и, следовательно, не будет повторно отображать эту строку.

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

Другие вопросы по теме