Использование оператора распространения в useEffect в ReactJS - PullRequest
0 голосов
/ 26 января 2020

Мне нужно вывести список 200 знаменитостей из API. Я уже однажды рендерил список из 20 знаменитостей, поэтому я обновил useEffect, как показано ниже, чтобы получить 200 вместо 20

Однако ничего не отображается, когда я не использую оператор распространения, он только рендерит, когда я их использую и я не понимаю, почему я должен использовать 2 копии моей переменной знаменитости и оператора res.data.results с распространением, чтобы она работала

Может кто-нибудь объяснить мне это?

Примечание: res.data.results - это массив объектов, которые я вызываю для отображения списка знаменитостей со всеми свойствами, связанными с ним (имя, изображение, известные фильмы и т. Д. c ..). Спасибо вам очень нравится!

const Celebrities = () => {
    const [celebrities, setCelebrities] = useState([])
    const [selectedCelebId, setSelectedCelebId] = useState(null)

    useEffect(() => {
        for (let page = 1; page <= 10; page++) {
            axios.get(`https://api.themoviedb.org/3/person/popular?page=${page}&api_key=MY_API_KEY`)
                .then(res => {
                    setCelebrities(celebs => [
                        ...celebs,
                        ...res.data.results
                        
                    ])
                })
                .catch(err => console.log(err))
        }
    }, [])
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Ответы [ 3 ]

1 голос
/ 26 января 2020

Прежде всего, вы запускаете несколько асинхронных вызовов одновременно. Я не знаю, если это то, что вы хотите сделать, но учтите, что они могут разрешаться в другом порядке, в котором вы их называете (т.е. запрос на страницу 3 может закончиться sh до запроса на страницу 1).

Теперь с вопросом оператора распространения. Вы обновляете состояние, вызывая setCelebrities с формой обратного вызова. Ваше состояние celebrities является массивом, поэтому вы хотите обновить его с помощью массива.

setCelebrities(celebs => [
    ...celebs,
    ...res.data.results
])

С помощью этого кода вы создаете новый массив, где первая часть - это элементы, которые у вас уже были (вот почему вы Нужно использовать оператор распространения, поэтому элементы, которые у вас были, деструктурированы) и результаты, которые вы получаете от API (который также является массивом, поэтому вам нужно деструктурировать). Если вы не разберетесь с ними, у вас получится массив массивов.

Если вы не хотите использовать оператор распространения, вы можете использовать метод concat:

setCelebrities(celebs => celebs.concat(res.data.results));
1 голос
/ 26 января 2020

Поскольку вы делаете 10 разных запросов, вам нужно объединить, а не заменить текущий результат предыдущими, следовательно, использовать распространение или конкат.

Однако у вас есть 2 проблемы:

  1. Вы устанавливаете состояние (setCelebrities) несколько раз. Хотя некоторые из этих вызовов будут пакетными, другие могут вызвать ненужные частичные визуализации.
  2. Поскольку вы делаете 10 параллельных звонков, некоторые из них могут завершить sh из-за неупорядоченности, что приведет к тому, что список знаменитостей выйдет из строя.

Я бы предложил собирать обещания в массив, а затем использовать Promise.all(), чтобы дождаться разрешения всех запросов, а затем взять массив результатов, сгладить его с помощью Array.flat() и установить состояние.

Пример (не проверено):

useEffect(() => {
  const promises = []

  for (let page = 1; page <= 10; page++) {
    const promise = axios.get(`https://api.themoviedb.org/3/person/popular?page=${page}&api_key=MY_API_KEY`)
    .then(res => res.data.results) // create a promise that will hold the results

    promises.push(promise) // push the promise to the array of promises
  }

  Promise.all(promises) // wait for promises to resolve, and get an array of results
    .then(results => setCelebrities(results.flat())) // flat the array and set the state
}, [])
1 голос
/ 26 января 2020

Если я понимаю, что вы говорите, вы не можете понять использование оператора распространения. Делая это

setCelebrities(celebs => [ ...celebs, ...res.data.results ])

, вы говорите:

  • возьмите моих предыдущих знаменитостей (знаменитостей)
  • и верните новый массив [], содержащий мои предыдущие знаменитости объекты (... знаменитости) и мои новые объекты знаменитостей (..res.data.results) и этот массив будет установлен как новое значение переменной знаменитости.

Если вы этого не сделаете вот так вы получите массив, содержащий два массива.

...