Files
MorphDoc/apps/web/src/use-markdown-render.ts
T

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 };
}