69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import type { RenderedMarkdownDocument } from "@md-to-pdf/core";
|
|
|
|
export interface MarkdownRenderCallbacks {
|
|
onRenderStart?: () => void;
|
|
onStatusChange?: (status: string) => void;
|
|
}
|
|
|
|
export function useMarkdownRender(
|
|
markdown: string,
|
|
language: string,
|
|
callbacks: MarkdownRenderCallbacks = {}
|
|
) {
|
|
const [result, setResult] =
|
|
useState<RenderedMarkdownDocument | null>(null);
|
|
const [error, setError] = useState("");
|
|
const { onRenderStart, onStatusChange } = callbacks;
|
|
|
|
useEffect(() => {
|
|
const controller = new AbortController();
|
|
const timer = window.setTimeout(() => {
|
|
onStatusChange?.("正在渲染…");
|
|
onRenderStart?.();
|
|
setError("");
|
|
|
|
void fetch("/api/render", {
|
|
method: "POST",
|
|
headers: {
|
|
"content-type": "application/json"
|
|
},
|
|
body: JSON.stringify({ markdown, language }),
|
|
signal: controller.signal
|
|
})
|
|
.then(async (response) => {
|
|
const payload = (await response.json()) as
|
|
| RenderedMarkdownDocument
|
|
| { message?: string };
|
|
if (!response.ok) {
|
|
throw new Error(
|
|
"message" in payload
|
|
? payload.message ?? "渲染失败"
|
|
: "渲染失败"
|
|
);
|
|
}
|
|
return payload as RenderedMarkdownDocument;
|
|
})
|
|
.then((payload) => {
|
|
setResult(payload);
|
|
onStatusChange?.("预览已更新");
|
|
})
|
|
.catch((reason: unknown) => {
|
|
if (!controller.signal.aborted) {
|
|
setError(
|
|
reason instanceof Error ? reason.message : "渲染失败"
|
|
);
|
|
onStatusChange?.("预览失败");
|
|
}
|
|
});
|
|
}, 250);
|
|
|
|
return () => {
|
|
window.clearTimeout(timer);
|
|
controller.abort();
|
|
};
|
|
}, [language, markdown, onRenderStart, onStatusChange]);
|
|
|
|
return { error, result };
|
|
}
|