Это компонент, который я воспроизвел:
import Image from "next/image";
import { useState } from "react";
export default function Home() {
const [downloadURL, setDownloadURL] = useState("");
const download = async () => {
const result = await fetch("http://localhost:3000/test.jpg", {
method: "GET",
headers: {},
});
const blob = await result.blob();
const url = URL.createObjectURL(blob);
setDownloadURL(url);
};
const handleDownload = async (e) => {
try {
await download();
URL.revokeObjectURL(downloadURL);
} catch (error) {
console.error(error);
}
};
return (
<div className = " bg-gray-500 bg-opacity-75 transition-opacity flex flex-col justify-center items-center">
<Image src = "/test.jpg" width = {500} height = {600} className = "mb-2 " />
<button
onClick = {handleDownload}
type = "button"
className = "flex-1 content-center text-center bg-indigo-600 py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
>
<a href = {downloadURL} download = {"test"}>
Download Image
</a>
</button>
</div>
);
}
в первый клик я загружаю .html
файл, а в следующие клики загружаю изображение. но я не мог понять, что вызывает первый щелчок при загрузке файла html
.
@SergeySosunov, какое решение?
Несколько ошибок при таком подходе:
click
обрабатывается <a>
перед <button>
onClick.<a>
href, который привязан к состоянию, но состояние не обновляется сразу, оно будет обновлено только при следующем рендере, но событие клика не будет ждать этого (пропуская тот факт, что это делается с помощью асинхронной операции).Что я рекомендую: полностью удалить <a>
и использовать старую классическую функцию скачать, которая создает <a>
на лету и выполняет «щелчок» по нему:
function Home() {
const download = (filename, content) => {
var element = document.createElement("a");
element.setAttribute("href", content);
element.setAttribute("download", filename);
element.style.display = "none";
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
};
const handleDownload = async (e) => {
try {
const result = await fetch("assets/test.png", {
method: "GET",
headers: {}
});
const blob = await result.blob();
const url = URL.createObjectURL(blob);
download("test", url);
URL.revokeObjectURL(url);
} catch (error) {
console.error(error);
}
};
return (
<div>
<img src = "/assets/test.png" width = {100} height = {100} />
<button onClick = {handleDownload} type = "button">
Download Image
</button>
</div>
);
}
Извините, что немного упростил ваш код.
Событие всплывает, <a download> находится внутри <button>, поэтому, когда вы нажимаете — по умолчанию выполняется обработчик <a download>, с пустым URL-адресом загрузки из-за начального состояния, затем событие распространяется до кнопки — теперь кнопка onClick выполнено, установка URL-адреса загрузки и т. д., но фактическое событие загрузки уже произошло до этого времени.