Я создаю приложение на ReactJS, которое использует теги для организации фотографий. Моя структура данных состоит из трех частей: (1) фотографии, (2) теги и (3) «теги изображений», которые представляют собой отношения между фотографией и тегом. Для фотографий с идентификаторами 9, 12 и 35 и тегами 4, 5 и 6 соответственно объект imageTag будет выглядеть следующим образом:
const imageTags = [
{id: 1, imageId: 9, tagId: 4},
{id: 2, imageId: 12, tagId: 5},
{id: 3, imageId: 35, tagId: 6}
]
Компоненту «Тег» передается только идентификатор imageTag, по которому он сможет определить изображение, которому он назначен, и тег, который должен быть на этом изображении, например:
// props: imagetagId = {7}
const imageId = imageTags.find(element => element.id === props.imageTagId)
Это отлично работает для первоначального рендеринга. Однако когда пользователь пытается удалить метку с фотографии*, состояние приложения меняется, и я внезапно получаю сообщение об ошибке:
Uncaught TypeError: element is undefined
Чего я не понимаю, так это того, как «элемент» может быть неопределенным? Насколько я понимаю, он проходит через объект imageTags и проверяет каждый «элемент», поэтому я так назвал переменную. Я знаю, что это НЕ проблема «imageTags.find(...) не определена», дело не в том, что метод find не возвращает результатов. Для меня ошибка выглядит так, как будто сам элемент не определен... но как это возможно?
Вот функция, которая изменяет imageTags, когда пользователь пытается удалить тег:
// remove a specific imageTag from imageTags
const handleRemoveTag = (imageTagId) => {
for (const [key, value] of Object.entries(imageTags)) {
if (value.id == imageTagId) {
delete imageTags[key];
};
};
};
*еще одна важная деталь, которую я обнаружил: эта ошибка НЕ возникает при удалении ПОСЛЕДНЕГО тега в списке. Теги можно безопасно удалять по одному, начиная с последнего и заканчивая первым, но удаление тега из середины или начала приводит к этой ошибке. Я не уверен, почему это так, но это кажется актуальным для устранения неполадок.
В частности, это на самом деле массив или то, что здесь показано?
Я немного упрощаю, чтобы облегчить понимание вопроса. Объект ImageTags вложен в объект, содержащий другие данные приложения, но при вызове соответствующих функций им передается только эта часть. @RobbyCornelissen, что делает JavaScript недействительным? Возможно, я просто опечатал это в этом объяснении, я могу уточнить, если это не имеет смысла.
Это недопустимое объявление объекта, поскольку в нем отсутствуют ключи. Это недопустимое объявление массива, поскольку в нем используются фигурные скобки. Поэтому люди не знают, что вы собираетесь использовать.
@RobbyCornelissen ах, понятно, да, это имеет смысл. Я дважды проверил код, и это массив объектов в коде. Я отредактировал свой вопрос, чтобы отразить это. Однако функция handleRemoveTag возвращает объект с ключом 0, например: imageTags = {0: {id: 1 ...}, {id: 2}}
Может ли это несоответствие быть причиной ошибки, с которой я столкнулся?
На самом деле, если вы просто удалите ключ из массива (не меняя длину или тому подобное), вы легко столкнетесь с аналогичной ошибкой. Например: let a = [1,2]; delete a[a.length-1]; a.find(element=>element.key)
. Здесь a.length
по-прежнему 2
, но a[1]
дает неопределенное значение.
Почему imageTags
не может быть Array
?
const imageTags = [ // <—-
{id: 1, imageId: 9, tagId: 4}, // |
{id: 2, imageId: 12, tagId: 5}, // |—- Array of Objects.
{id: 3, imageId: 35, tagId: 6} // |
] // <—-
Чтобы удалить конкретный imageTag
из imageTags
, если это Array
, используйте эту процедуру.
const handleRemoveTag = (imageTagId) => {
let index = imageTags.findIndex(element => element.id === imageTagId)
imageTags.splice(index, 1)
}
Я только что попробовал это быстро и получаю ту же ошибку. Я попробую еще раз завтра, когда у меня будет больше времени, чтобы выявить потенциальные ловушки, которые я мог упустить. Когда я console.info(ImageTags), он говорит «Массив», поэтому его можно настроить так, как он у вас есть, но когда я console.info(typeof ImageTags), он говорит «объект», так что я не уверен. Скоро я смогу рассмотреть его более подробно и вернуться к вам.
Array
— это Object
. Вместо этого проверьте Array.isArray
.
Могу подтвердить, это массив, а не словарь. Я обновил свой вопрос, чтобы отразить, как на самом деле настроен код. Однако я заметил, что результат, возвращаемый функцией handleRemoveTag, представляет собой словарь, например: {0: {id:1 ...}, {id: 2...}}
Может ли это быть причиной этой ошибки? Это вызвано тем, что я пытаюсь использовать Object.entries, и исправляет ли это ваше решение? (Попробую это сейчас, чтобы посмотреть, смогу ли я сам ответить на эти вопросы с помощью кода)
Поскольку вы сделали imageTags
Array
, как я советовал, почему вы все еще используете Object.entries
? Почему бы не использовать интерфейс Array
? Я поделился возможной реализацией в своем ответе, не так ли? Используй это.
Я вставил вашу реализацию. (Извините за задержку, это личный проект, и у меня есть на него совсем немного времени.) Я наблюдаю то же поведение, что описано в исходном вопросе, я могу удалять теги, начиная с последнего, назначенного изображению. и безопасно вернуться назад, но если я попытаюсь удалить первый тег, назначенный изображению, перед удалением последнего, все произойдет сбой.
Поиграв еще немного с этим, я получил кое-что для работы, основываясь на вашем ответе! Спасибо за вашу помощь в этом!
Это объявление
imageTags
не является действительным JavaScript.