Почему для списков в Redux следует использовать объект, а не массив

То же самое относится и к любому инструменту управления состоянием.

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

Наиболее распространенная структура данных для списков в Javascript - это массив.

Я хотел бы объяснить, почему это может быть не лучшим выбором при хранении этих списков в инструменте управления состоянием, таком как Redux или React Context.

C [RUD] операции с одним элементом

Если вы хотите выполнить одну из операций RUD (чтение, обновление или удаление) для одного элемента, вам всегда нужно выполнять итерацию.

За исключением создания, где вам просто нужно добавить элемент в список.

Читать

Если вы используете массив, вам нужно найти этот элемент с помощью фильтрации. Когда у вас есть объект, вам нужен только идентификатор, который вы использовали в качестве ключа.

Обновлять

При использовании массива самый быстрый способ - отобразить и изменить тот, который вы хотите изменить. Для объекта просто установите свойство, указывающее на обновленный элемент.

Удалить

Фильтр для массива. Просто удалите этот ключ для объекта.

Получение из API

Вот где использование объекта превосходит использование массива.

Когда ваши элементы поступают из серверной части, вам нужно их получить. Что произойдет, если вы принесете один и тот же предмет дважды? Или один и тот же список дважды? Или список с дублированными и новыми элементами?

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

Как насчет того, чтобы добавить к объекту один и тот же элемент дважды?

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

Когда НЕ использовать объект

Если у вас нет уникального идентификатора для каждого элемента. Или вы хотите вести заказ, не используя лишнее свойство.

Примеры кода

Давайте посмотрим на несколько примеров кода. В следующих примерах кода представлены только операции, описанные выше. Они НЕ являются редукторами редукции или другими создателями состояний. Это всего лишь несколько фрагментов, чтобы лучше понять мысль, о которой я говорю выше.

У нас есть список комментариев.

// array
const comments = [
  { id: '1', text: 'add code examples' },
  { id: '2', text: 'examples would be great for this article' },
  { id: '3', text: 'hi there' },
];
// object
const comments = {
  '1': { id: '1', text: 'please add code examples' },
  '2': { id: '2', text: 'examples would be great for this article' },
  '3': { id: '3', text: 'hi there' },
};

Читать комментарий id 2

const commentId = '2';
// array
comments.find((comment) => comment.id === commentId)
// object
comments[commentId];

Обновить идентификатор комментария 1

const updatedComment = { id: '1', text: 'add code examples, please' };
// array
comments.map((comment) => {
  if (comment.id === updatedComment.id) {
    return updatedComment;
  }
  return comment;
});
// object
comments[updatedComment.id] = updatedComment;

Удалить идентификатор комментария 3

const commentId = '3';
// array
comments.filter((comment) => comment.id !== commentId);
// object
delete comments[commentId];

Добавление нового комментария

Мы должны предположить, что не знаем, существует он уже или нет.

const newComment = { id: '4', text: 'thanks for the code examples!' };
// array
if (comments.find((comment) => comment.id === newComment.id) {
  comments = comments.map((comment) => {
    if (comment.id === newComment.id) {
      return newComment;
    }
    return comment;
  });
} else {
  comments = comments.concat([newComment]);
}
// object
comments[newComment.id] = newComment;

Что, если вам нужен массив где-то в вашем коде?

Иногда может оказаться, что для списка элементов проще использовать массив. Например, когда вы визуализируете список. Легче иметь массив, использовать карту и создавать элемент на каждой итерации.

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

Селектор - это функция, которая принимает какое-то состояние и возвращает нужные вам данные. Обычно в нужной схеме или структуре.

// object
const comments = {
  '1': { id: '1', text: 'please add code examples' },
  '2': { id: '2', text: 'examples would be great for this article' },
  '3': { id: '3', text: 'hi there' },
};
// transform to array
const commentsSelector = (commentsObj) => {
  return Object.keys(commentsObj)
    .map((commentKey) => commentsObj[commentKey]);
};
// usage of the selector
const commentsArray = commentsSelector(comments);

Заключение

Использование объекта сэкономит время и избавит вас от ошибок в будущем. Сделайте ей одолжение и используйте предмет для хранения списка предметов.

Даже новичку я рекомендую вам использовать объекты вместо массивов для хранения списков элементов. В конце концов, борьба окупается. Как и большинство проблем :)

Подробнее о лучших практиках в формах состояний в Redux Docs on Normalization.

Спасибо за чтение. Хотелось бы услышать ваши мысли в комментариях.

Если вам понравилась эта статья, подумайте о подписке на мой информационный бюллетень на GIMTEC.