React.JS: вложенные массивы фильтров / карт

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

По сути, у меня есть вызов API, который возвращает массив объектов в качестве обещания, я сопоставляю или фильтрую их (я пробовал оба), и мне нужно найти элементы, которые уже существуют в массиве booksOnShelves. Я делаю это, сравнивая свойство .id каждого объекта. Как только мы найдем совпадение, мне нужно установить для свойства .shelf то же значение, что и в существующем массиве, и если книга не существует, мне нужно установить его значение на 'none'. Здесь все хорошо, но проблема в том, что когда я нахожу совпадение, свойство обновляет shelf до правильного, но итерация продолжается со следующей книгой, которая, очевидно, не совпадает, и перезаписывает значение .shelf без нуля.

Вот код этого конкретного метода:

class SearchBar extends Component {
  state = {
    query: '',
    result: []
  }

  getBooks = (query) => {
    const booksOnShelves = this.props.books;

    BooksAPI.search(query)
    .then(res => {
      if (res instanceof Array && res.length > 0) {
        res.filter( searchedBooks => {
          return booksOnShelves.filter( onShelves => {
            if ( searchedBooks.id === onShelves.id) {
              return searchedBooks.shelf = onShelves.shelf
            } else {
              return searchedBooks.shelf = 'none
            }
          })
        })
        this.setState({result: res.sort(sortBy('title'})
      } else {
        this.setState({result: []})
      }
    })
    .catch( err => { console.info('ERROR: ', err)})
  }

Я пробовал так много вещей, но ни один не смог сохранить ценность свойства полки.

Есть ли способ остановить итерацию от перезаписи совпадающего значения?

Есть идеи, как достичь желаемого результата?

Заранее благодарю за помощь.

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

rodcunha 14.06.2018 00:18
array.filter - это не то, что вам нужно. Эта функция будет извлекать элементы из массива, когда вы вернете false внутри функции, и сохранит элементы в массиве, когда вы вернете true.
Blundering Philosopher 14.06.2018 00:40

Я также немного смущен вашей строкой this.setState({result: res.sort(sortBy('title'}), поскольку, похоже, там отсутствуют некоторые символы ). Вы хотите, чтобы это был this.setState({result: res.sort(sortBy('title'))})? (обратите внимание на 2 дополнительных символа )

Blundering Philosopher 14.06.2018 00:44

Вы можете использовать Array.find(), который возвращает первый соответствующий объект. Он прекратит итерацию, как только найдет совпадение. Попробуйте поэкспериментировать с этим, где вы вызываете .filter() вместо filter.

agm1984 14.06.2018 00:49

Blundering Philosopher да, отсутствие пары символов в этой строке, спасибо, было проблемой при копировании кода, фактический код правильный. agm1984 Попробую использовать фильтр, спасибо.

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

Ответы 2

Должно работать нормально в вашем случае:

BooksAPI.search(query).then(res => {
if (res instanceof Array && res.length > 0) {
  booksOnShelves.forEach((book) => {
    const correspondingRes = res.find((item) => { return (item.id === book.id) });
    if (correspondingRes) {
      book.shelf = correspondingRes.shelf;
    } else {
      book.shelf = “none”;
    }
  });
}

Я думаю, что в заявлении else OP хочет, чтобы book.shelf = 'none';, верно?

Blundering Philosopher 14.06.2018 00:42

Спасибо за ответ l1fe, но я не думаю, что это сработает. booksOnShelves уже имеет свойство .shelf, и его необходимо добавить к результату обещания res, возвращаемого вызовом API. API возвращает объект без .shelf, поэтому нам нужно либо ничего не вернуть, либо, если книги совпадают, им нужно вернуть значение полки для соответствующей книги в booksOnShelves, которое представляет собой массив, переданный как опора этому компоненту. Имеет ли это смысл? Я пытался использовать и реорганизовать ваш код, но все равно не смог заставить его работать, я буду продолжать попытки. Еще раз спасибо.

rodcunha 14.06.2018 10:36
Ответ принят как подходящий

Проблема решена с помощью всех вас, ребята, я заставил ее работать. Большое спасибо.

Просто для справки вот код, который работал.

    BooksAPI.search( query )
  .then( res => {
    if (res instanceof Array && res.length > 0) {
        res.map( booksFromSearch => {
          booksOnShelves.find( book => {
            if ( booksFromSearch.id === book.id) {
              booksFromSearch.shelf = book.shelf
              return booksFromSearch;
            } else {
              booksFromSearch.shelf = 'none'
            }
          })
        })

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