Обновлено, чтобы отразить форму объекта, возвращаемого вашим вызовом API.
Один из способов справиться с этим, как показано ниже, состоит в замене метаданных страницы (page
, total_results
, * 1005). *) в состоянии вашего компонента с информацией о последнем вызове API, но append results
каждый раз.
Если вам не нужна информация о подкачке, вы можете просто отбросить ее на полу и сохраняйте только результаты, но сохраняя их, вы сможете отображать информацию о подкачке и отключать кнопку «загрузить больше», когда доберетесь до конца.
Отображение текущей страницы и всего страниц может не иметь смысла учитывая, что вы просто добавляете к списку (и, следовательно, на самом деле не «разбиваете на страницы» в смысле пользовательского интерфейса), но я включил его здесь просто для того, чтобы дать представление о том, как вы можете использовать эту информацию, если решите это сделать.
Ключевым моментом во фрагменте ниже, который относится к вашему исходному вопросу, является слияние состояний:
const more = () => {
fetchTopRatedMovies(page + 1)
.then(newData => {
setData({
// copy everything (page, total_results, total_pages, etc.)
// from the fetched data into the updated state
...newData,
// append the new results to the old results
results: [...data.results, ...newData.results]
});
});
}
Я использую синтаксис распространения , чтобы скопировать все поля сюда m newData
в новое состояние, а затем отдельно обрабатывать поле results
, потому что мы хотим заменить его объединенными результатами. (Если вы пропустите строку results: [...data.results, ...newData.results]
, ваше новое состояние будет иметь поле результатов от newData
. Указывая поле results
после ...newData
, вы заменяете его на объединенный массив.
Надеюсь, это поможет.
/*
Your api returns an object with the following shape.
I don't know what the individual results entries look like,
but for our purposes it doesn't really matter and should be
straightforward for you to tweak the following code as needed.
{
page: 1,
total_results: 5175,
total_pages: 259,
results: [
{
title: 'Scott Pilgrim vs. The World',
year: 2010,
director: 'Edgar Wright'
},
{
title: 'Spiderman: Into the Spider-Verse',
year: 2018,
director: ['Bob Persichetti', 'Peter Ramsey', 'Rodney Rothman']
},
{
title: 'JOKER',
year: 2019,
director: 'Todd Phillips'
},
];
}
*/
const {useState} = React;
// simulated api request; waits half a second and resolves with mock data
const fetchTopRatedMovies = (page = 0) => new Promise((resolve) => {
// 5 is arbitrary
const numPerPage = 5;
// generate an array of mock results with titles and years
const results = Array.from(
{length: numPerPage},
(_, i) => ({
title: `Movie ${(page - 1) * numPerPage + i}`,
year: Math.floor(Math.random() * 20) + 2000
})
);
// 16 is arbitrary; just to show how you can disable
// the 'more' button when you get to the last page
const total_results = 16;
// the return payload
const data = {
page,
total_results,
total_pages: Math.floor(total_results / numPerPage),
results
}
setTimeout(() => resolve(data), 500);
});
const Demo = () => {
const [data, setData] = useState({ page: 0, results: [] });
const more = () => {
fetchTopRatedMovies(page + 1)
.then(newData => {
setData({
// copy everything (page, total_results, total_pages, etc.)
// from the fetched data into the updated state
...newData,
// append the new results to the old results
results: [...data.results, ...newData.results]
});
});
}
// pull individual fields from state
const {page, results, total_results, total_pages} = data;
// are there more pages? (used to disable the button when we get to the end)
const hasMore = page === 0 || (page < total_pages);
return (
{total_pages && (
Page: {page} of {total_pages}
Total: {total_results}
)}
{results.map(m => (
{m.title} - ({m.year})
))}
component state:
{JSON.stringify(data, null, 2)}
); }; ReactDOM.render ( , document.getElementById ('demo'));
/* purely cosmetic. none of this is necessary */
body {
font-family: sans-serif;
line-height: 1.6;
}
.wrapper {
display: flex;
background: #dedede;
padding: 8px;
}
.wrapper > * {
flex: 1 1 50%;
background: white;
margin: 8px;
padding: 16px;
}
h3 {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.0/umd/react-dom.production.min.js"></script>
<div id="demo" />