Для запуска функции ReactJS требуется двойной щелчок мыши

У меня есть 2 функции: функция uploadFile загружает изображение файла в Firebase, а затем сохраняет возвращенный URL-адрес через setState, и функция saveTeam, которая отправляет запрос /new-team-member с полезной нагрузкой, включая возвращенный URL-адрес.

const uploadFile = async () => {
  const imageRef = storageRef(storage, `images/${UniqueComponentId()}`);
  uploadBytes(imageRef, team.image)
    .then((snapshot) => {
      getDownloadURL(snapshot.ref)
        .then((url) => {
          setTeam({ ...team, url: url || team.image });
        })
        .catch((error) => {
          console.info(error.message);
        });
    })
    .catch((error) => {
      console.info(error.message);
    });
};

const saveTeam = async () => {
  setSubmitted(true);
  let _teams = [...teams];
  let _team = { ...team };
  if (team.id) {
    await fetch('https://bunaq-api.vercel.app/api/edit-team-member', {
      method: 'PUT',
      body: JSON.stringify(team),
      headers: { 'Content-Type': 'application/json' },
    });
    const index = findIndexById(team.id);
    _teams[index] = _team;
    toast.current.show({
      severity: 'success',
      summary: 'Successful',
      detail: t('adminTeamPage.new.toastUpdated'),
      life: 5000,
    });
  } else {
    fetch('https://bunaq-api.vercel.app/api/new-team-member', {
      method: 'POST',
      body: JSON.stringify(team),
      headers: { 'Content-Type': 'application/json' },
    });
    _teams.unshift(_team);
    // location.reload();
    toast.current.show({
      severity: 'success',
      summary: 'Successful',
      detail: t('adminTeamPage.new.toastCreated'),
      life: 5000,
    });
  }
  setTeams(_teams);
  setTeamDialog(false);
  setTeam(emptyTeam);
};

const saveTeamMain = async () => {
  await uploadFile();
  saveTeam();
};

<button onClick = {saveTeamMain}>Save</button>;

Но когда я нажимаю Save в первый раз, он ничего не делает, а затем запускает функцию при втором нажатии, почему это происходит?

Судя по вашему описанию, вам следует дождаться завершения (предположительно) асинхронной функции uploadFile(). Если это сохранит URL-адрес в состоянии, вам также нужно будет правильно дождаться изменения этого состояния с помощью перехватчика эффекта, прежде чем вызывать saveTeam(). Однако для этого вопроса действительно нужен минимальный воспроизводимый пример, чтобы полностью его понять.

Phil 08.05.2024 02:57

Есть ли ошибки в консоли Javascript? Выработайте привычку читать ошибки, не игнорируйте их, как сейчас!

Andy Ray 08.05.2024 03:01

Отвечает ли это на ваш вопрос? Метод установки useState не отражает изменение немедленно

Phil 08.05.2024 03:02

моя проблема в том, что функция работает в 2 клика, когда я нажимаю save в первый раз, ничего не происходит и никаких ошибок, когда я нажимаю ее после этого (второй раз), все работает нормально

johnny shepherd 08.05.2024 03:05

пожалуйста, прочитайте заголовок моего вопроса, если бы это было «почему setState не отражает изменения», тогда ваши ответы были бы актуальными

johnny shepherd 08.05.2024 03:11

Кажется, вы не прочитали сообщение по ссылке. Вызов setTeam() не применит изменения к team до следующего цикла рендеринга. Вам нужно использовать хук эффекта, чтобы следить за изменениями team. Вы также не ждете, пока обещание uploadBytes() разрешится.

Phil 08.05.2024 03:13
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
3
7
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой вам придется щелкнуть дважды, заключается в том, что даже если вы ждете uploadFile, поскольку для загрузки файла используются .then и .catch, он немедленно возвращается и запускается saveTeam непосредственно перед завершением uploadFile. Таким образом, все настройки состояния, происходящие в uploadFile, происходят после запуска saveTeam.

Вам следует преобразовать uploadFile в синтаксис ожидания.

const uploadFile = async () => {
  const imageRef = storageRef(storage, `images/${UniqueComponentId()}`);
try{
  const snapshot = await uploadBytes(imageRef, team.image)
  const url = await getDownloadUrl(snapshot.ref)
  setTeam({...team, url:url || team.image})
  return

  }catch(err){
    console.info(err.message)
  }
};

Даже при правильном ожидании uploadFile, если вы ожидаете установить состояние в uploadFile, тогда прочитайте это состояние в синхронно вызываемой функции saveTeam. Я считаю, что у вас все равно будет устаревшее состояние.

да, его состояние все еще будет устаревшим, решение этой проблемы, как упомянул @Phill, должно быть вставлено в функцию saveTeamuseEffect

johnny shepherd 08.05.2024 14:40

Также можно просто вернуть необходимые значения из uploadFile и передать их saveTeam в качестве аргументов. Из предоставленного им кода также неясно, должны ли эти значения вообще иметь состояние.

Scott Z 08.05.2024 15:16

Причина, по которой я подозреваю, что некоторые из этих значений не нуждаются в сохранении состояния, заключается в том, что он устанавливает команду в uploadFile, а затем сразу же устанавливает команду в emptyTeam в saveTeam. Если эти значения не предназначены для изменения DOM, нет смысла использовать состояние. Лучше использовать ссылку или просто вернуть значения из uploadFile и использовать их с помощью saveTeam.

Scott Z 08.05.2024 15:30

Другие вопросы по теме