У меня есть 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 в первый раз, он ничего не делает, а затем запускает функцию при втором нажатии, почему это происходит?
Есть ли ошибки в консоли Javascript? Выработайте привычку читать ошибки, не игнорируйте их, как сейчас!
Отвечает ли это на ваш вопрос? Метод установки useState не отражает изменение немедленно
моя проблема в том, что функция работает в 2 клика, когда я нажимаю save в первый раз, ничего не происходит и никаких ошибок, когда я нажимаю ее после этого (второй раз), все работает нормально
пожалуйста, прочитайте заголовок моего вопроса, если бы это было «почему setState не отражает изменения», тогда ваши ответы были бы актуальными
Кажется, вы не прочитали сообщение по ссылке. Вызов setTeam() не применит изменения к team до следующего цикла рендеринга. Вам нужно использовать хук эффекта, чтобы следить за изменениями team. Вы также не ждете, пока обещание uploadBytes() разрешится.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Причина, по которой вам придется щелкнуть дважды, заключается в том, что даже если вы ждете 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
Также можно просто вернуть необходимые значения из uploadFile и передать их saveTeam в качестве аргументов. Из предоставленного им кода также неясно, должны ли эти значения вообще иметь состояние.
Причина, по которой я подозреваю, что некоторые из этих значений не нуждаются в сохранении состояния, заключается в том, что он устанавливает команду в uploadFile, а затем сразу же устанавливает команду в emptyTeam в saveTeam. Если эти значения не предназначены для изменения DOM, нет смысла использовать состояние. Лучше использовать ссылку или просто вернуть значения из uploadFile и использовать их с помощью saveTeam.
Судя по вашему описанию, вам следует дождаться завершения (предположительно) асинхронной функции
uploadFile(). Если это сохранит URL-адрес в состоянии, вам также нужно будет правильно дождаться изменения этого состояния с помощью перехватчика эффекта, прежде чем вызыватьsaveTeam(). Однако для этого вопроса действительно нужен минимальный воспроизводимый пример, чтобы полностью его понять.