Визуализировать элементы из массива объектов, используя другой массив с идентификаторами: ошибка ts и рекомендации

Я делаю проект библиотеки (см. ссылку для получения дополнительной информации) с react, redux-toolkit и typescript.

Я делаю функционал addToWishlist: пользователь просто нажимает на звездочку, код отправляет действие, которое исправляет базу данных, и состояние обновляется. Есть еще одно действие по удалению книги из списка.

В компоненте <Wishlist /> я, конечно, хочу отобразить заголовки и другие данные каждой книги. Итак, я useAppSelector извлекаю wishlist и все list книг, и с помощью filter и map я получаю соответствующие книги, но я не могу их отобразить, потому что это дает мне ts ошибку: index.d.ts(1373, 9): The expected type comes from property 'children' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLUListElement>, HTMLUListElement>'

Важное замечание о структуре

wishlist — это массив строк, представляющих собой идентификаторы книг. Вместо этого весь list книг представляет собой массив объектов: каждый объект представляет собой книгу с названием, автором, идентификатором и т. д.

Мои вопросы:

  1. Что здесь происходит не так?

  2. В принципе, лучше ли сохранять идентификаторы в массиве wishlist (как я сделал), поэтому мне нужно получить данные книг в моем компоненте <Wishlist /> с помощью filter и map, или лучше сохранить всю книгу ( или, по крайней мере, информацию, которая мне нужна), чтобы было легче иметь данные?

  3. Как лучше всего отображать список в первом случае, когда мне нужно извлекать данные с помощью filter и map?

Вот попытка:

const Wishlist = () => {
  const dispatch = useAppDispatch();
  const wishlist = useAppSelector(state => state.user.userInfo.wishlist);
  const list = useAppSelector(state => state.catalogue.list);

  const renderBooks = () => {
    return wishlist.map(wishId => {
      list.filter(book => {
        if (book.id === wishId) {
          return (
            <li>{book.title}</li>
          )
        }
      })
    })
  }

  
  return (
    <ul>
      {renderBooks()}
    </ul>
  )
};

export default Wishlist;

Отредактировал - может проблема не в конкатенации методов, а что-то в вызове функции?

Еще один небольшой пример с другим решением, но с той же проблемой

interface fakeObj {
    id: string;
    name: string;
  }
  const fakeIds = ['5', '12', '878'] // this is my 'wishlist', containing only ids
  const fakeList: fakeObj[] = [ // this is my 'list', containing objects, which were single books
    { id: '334', name: 'Tony' },
    { id: '5', name: 'Milly' },
    { id: '12', name: 'Jack' },
    { id: '7', name: 'Stew' },
    { id: '878', name: 'Mark' },
    { id: '87998', name: 'Greg' }
  ]

  const renderArray = () => {
    const arr: fakeObj[] = []; 
    fakeIds.forEach(id => {
      fakeList.filter(obj => {
        if (obj.id === id) {
          arr.push(obj)
        }
      })
    })
    return arr; // the returned array is what I want: an array continaing the objects that i need
  }

  return (
    <ul>
      {/* The problem actually is here! */}
      {renderArray()} 
    </ul>
  )

Первое, что вам нужно понять, когда использовать карту и фильтр и каков тип возвращаемого значения каждого метода. Вы хотите отобразить все книги с идентификаторами в wishlist. Сначала вам нужно отфильтровать книги, которые содержат идентификатор в списке желаний, используя фильтр (который возвращает книгу, если она удовлетворяет условию), а затем использовать карту. list.filter((book)=> wishlist.includes(book.id)).map((book)=> <li key = {book.id}>{book.title}</li>)Документация по методам массива

Muhammad Nouman Rafique 13.11.2022 03:26

Я редактирую свой ответ, чтобы сделать его более точным в отношении структур, но ваш метод в моем случае не работает, и я не уверен в логике. Я сделаю также пример, чтобы понять лучше.

ncasteln 13.11.2022 17:50
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
2
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы неправильно используете .filter() или .map(), что и вызывает ошибки.

Комментарий выше, который вы отвергли, был правильным решением этой проблемы.

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

Итак, я возвращаюсь к исходному примеру.

Проблема №1:

Вы пытаетесь вернуть элемент JSX в обратном вызове, переданном в .filter(). Это не то, как работает .filter(). Вы должны передать обратный вызов .filter(), который вернет TRUE или FALSE в зависимости от того, хотите ли вы, чтобы элемент был отфильтрован или отфильтрован. Например. listOfCounts.filter( count => count > 5); вернет измененный массив всех элементов в listOfCounts, которые больше 5.

Проблема №2:

В настоящее время вы сначала вызываете .map(), что неправильно, но затем также вызываете .filter() ВНУТРИ .map() вместо того, чтобы связывать карту ПОСЛЕ фильтра. Потому что прямо сейчас ваш вызов .map() даже не пытается вернуть список элементов JSX, представляющих названия книг, которые вы хотите отобразить. Эти вызовы должны быть связаны противоположно тому, как вы это делаете. Пример очень простого использования .map():

listOfNames.map(name => <div>{name}</div>);

Простой пример объединения .map() с .filter():

listOfNames.filter(name => name[0] == 'J').map(name => <div>{name}</div>);

который отфильтровывает все имена, которые не начинаются с прописной буквы J.

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

Спасибо. На самом деле, проблема была (также) в том, что я попробовал решение Rafique, но renderBooks() все еще был подписан как ошибка TS, и я не могу отобразить результат, потому что, я думаю, я не указываю тип возвращаемого значения в функция. Затем я пытаюсь поместить код прямо в возврат, и это работает.

ncasteln 13.11.2022 19:03

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

Попытка переключить логическое значение Redux нажатием кнопки, однако переключение работает только в первый раз, и я не уверен, почему
Redux Saga: аргумент типа «строка» не может быть назначен параметру типа «TakeableChannel <неизвестно>»
Запрос передачи Redux-saga и параметры для тела POST
Получить постоянный accessToken Redux-Persists в файле определения API запросов RTK — хранить регидратацию, отличную от уровня компонентов
В React и Redux, какой наиболее эффективный способ сопоставления идентификатора элемента, на который ссылается форма нормализованного состояния?
Набор инструментов React-redux: невозможно установить новое состояние при передаче редуктора в качестве реквизита другой функции
Изменение состояния с условием в Redux Slice
Обновления медленные с Redux
RTK Query и Mutation последовательно
UseState становится доступным только для чтения после сохранения данных в инструментарий Redux