Добавить больше данных в состояние, сохраняя при этом оригинал (React) - PullRequest
0 голосов
/ 27 февраля 2020

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

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

Вот код

const TopRatedPage = () => {
  const [apiData, setApiData] = useState([]);
  const [isLoading, setLoading] = useState(false);
  const [pageNumber, setPageNumber] = useState(1);
  const { results = [] } = apiData;

  useEffect(() => {
    setLoading(true);
    fetchTopRatedMovies(pageNumber).then((data) => setApiData(data));
    setLoading(false);
  }, [apiData, pageNumber]);

  return (
    <div className='top-rated-page-wrapper'>
      <h1>TopRatedPage</h1>
      {isLoading ? <h1>Loading...</h1> : <MovieList results={results} />}
      <button
        onClick={() => {
          setPageNumber(pageNumber + 1);
        }}>
        MORE
      </button>
    </div>
  );

Я пробовал setApiData(...apiData,data), но выдает ошибку, apiData не может быть повторен кнопка, которая добавляет больше данных API для отображения и отображения большего количества данных.

1 Ответ

0 голосов
/ 27 февраля 2020

Обновлено, чтобы отразить форму объекта, возвращаемого вашим вызовом 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" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...