Почему моя функция срабатывает, даже если она находится внутри а.затем цепочка (обещание/асинхронность/ожидание)?

#javascript #async-await #promise

Вопрос:

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

Например, карты должны представлять собой массив из 102 элементов. Однако console.log(карты.длина) показывает 0. Кроме того, последнее .затем освобождается от ответственности до того, как какой-либо элемент будет помещен в карты.

   React.useEffect(() => {
    // if (!cards.length) {
    //https://api.pokemontcg.io/v2/cards?q=set.id:base1
    async function fetchCards() {
       const response = await fetch('https://api.pokemontcg.io/v2/cards?q=set.id:base1', {
        mode: 'cors',
        headers: {
          'X-Api-key': '22173ccf-376e-4d12-8d50-8b25df6a8e13',
        },
      })
        .then((res) => res.json())
        .then((data) => {
          console.log(data.data);
          setCards(data.data);
          console.log(cards.length);
        })
        .then(() => {
           updateDeck(getRandom(cards, 4));
        });
    }
    // }
    fetchCards()
  }, []);
 

Комментарии:

1. Основная часть fetchCards ничего не возвращает, поэтому первая .then() уже не получает данных для работы. Вместо const response = await fetch(...) того, чтобы просто return fetch(...) . На самом деле, зачем вообще нужны карточки? Просто имейте fetch(url, ...).then(response => response.json()).then(......) , не нужно объявлять и вызывать, у вас уже есть цепочка обещаний, начиная с fetch.

2. @Mike’Pomax’Camermans Я отредактировал код, но его длина по-прежнему равна 0.

3. Откуда это cards берется? Ваш then аргумент называется data «нет cards «, поэтому вы не показываете весь свой код , и я не собираюсь гадать, что делает остальное. Если setCards является функцией состояния, то да, очевидно, что связанная cards функция не будет обновлена в следующей строке: она будет обновлена при следующем вызове рендеринга, а не раньше. Вот как обновления состояния работают в React.

4. Простите мое полное невежество. вы имеете в виду, что я должен обернуть (res.json()) так, чтобы вернуть его?

5. карты, поступающие из инициализации useState const [карты, setCards] = React.useState([]);

Ответ №1:

  1. Вы не должны путать ваши async/await s с then обратными вызовами.
  2. Используйте новый useEffect , чтобы проверить, когда cards изменения вызовут вашу updateDeck функцию. setCards является асинхронным процессом, поэтому новое состояние будет доступно не сразу после его установки. Вот почему требуется дополнительная плата useEffect , когда состояние действительно меняется.

Вот сокращенный пример:

 useEffect(() => {
  async function fetchCards() {
    const res = await fetch(url, params);
    const data = await res.json();
    setCards(data.data);
  }
  fetchCards();
}, []);

useEffect(() => {
  if (cards.length) updateDeck(getRandom(cards, 4));
}, [cards]);
 

Комментарии:

1. Я об этом не подумал! Я попробую это сделать. Однако я отредактировал код, чтобы удалить ожидание/асинхронность, и оставил только .затем. Однако все равно не повезло. Есть идеи, почему?

2. setCards является асинхронным, поэтому новое состояние не будет доступно сразу же после его установки, поэтому useEffect для того, когда состояние изменится, требуется дополнительный параметр.

3. Должен ли я также использовать любую функцию, которую я хочу запустить на картах, во втором эффекте использования?

4. @капитан: К вашему сведению, я откатил вашу правку. Переполнение стека немного отличается от других форумов, которые вы, возможно, использовали, в том, что цель состоит в создании страниц с вопросами и ответами, которые полезны другим людям; поэтому, как только ответ опубликован, вы не должны редактировать свой вопрос, чтобы признать его недействительным. (Я имею в виду, что если ответ был результатом неправильного понимания вашего вопроса, то можно отредактировать вопрос, чтобы уточнить; но если вопрос касается ошибки, и ответ показывает, как ее исправить, то вы не должны редактировать вопрос, чтобы исправить эту ошибку и спросить о новой проблеме.)

5. второй эффект использования вызывается первым рендером и выдает ошибку, потому что карты пусты! есть ли способ заставить его ждать без условного условия?