Я пытаюсь изучить 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)})
}
Я пробовал так много вещей, но ни один не смог сохранить ценность свойства полки.
Есть ли способ остановить итерацию от перезаписи совпадающего значения?
Есть идеи, как достичь желаемого результата?
Заранее благодарю за помощь.
array.filter - это не то, что вам нужно. Эта функция будет извлекать элементы из массива, когда вы вернете false внутри функции, и сохранит элементы в массиве, когда вы вернете true.
Я также немного смущен вашей строкой this.setState({result: res.sort(sortBy('title'}), поскольку, похоже, там отсутствуют некоторые символы ). Вы хотите, чтобы это был this.setState({result: res.sort(sortBy('title'))})? (обратите внимание на 2 дополнительных символа )
Вы можете использовать Array.find(), который возвращает первый соответствующий объект. Он прекратит итерацию, как только найдет совпадение. Попробуйте поэкспериментировать с этим, где вы вызываете .filter() вместо filter.
Blundering Philosopher да, отсутствие пары символов в этой строке, спасибо, было проблемой при копировании кода, фактический код правильный. agm1984 Попробую использовать фильтр, спасибо.





Должно работать нормально в вашем случае:
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';, верно?
Спасибо за ответ l1fe, но я не думаю, что это сработает. booksOnShelves уже имеет свойство .shelf, и его необходимо добавить к результату обещания res, возвращаемого вызовом API. API возвращает объект без .shelf, поэтому нам нужно либо ничего не вернуть, либо, если книги совпадают, им нужно вернуть значение полки для соответствующей книги в booksOnShelves, которое представляет собой массив, переданный как опора этому компоненту. Имеет ли это смысл? Я пытался использовать и реорганизовать ваш код, но все равно не смог заставить его работать, я буду продолжать попытки. Еще раз спасибо.
Проблема решена с помощью всех вас, ребята, я заставил ее работать. Большое спасибо.
Просто для справки вот код, который работал.
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'
}
})
})
Кстати, я знаю, что использую фильтр только в примере кода, но я также безуспешно пытался использовать карту.