docs(ui): explain page and shared component lifecycle boundaries
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
import { Suspense } from "react";
|
||||
import GraphPage from "@/components/workspace/graph-page";
|
||||
|
||||
/** params按当前Next版本await;Suspense给客户端画布准备过程提供状态占位,不在此发模型请求。 */
|
||||
/** params按当前Next版本await;Suspense为子树渲染时的挂起提供占位,不在此发模型请求。
|
||||
* params 的 await 在此边界外;GraphPage 在 effect 中加载模型时的进度/错误由自身状态呈现。 */
|
||||
export default async function Page({ params }: { params: Promise<{ workspace: string; board: string }> }) {
|
||||
const { workspace, board } = await params;
|
||||
return (
|
||||
|
||||
@@ -8,7 +8,8 @@ import { ActiveBoardProvider } from "@/components/workspace/active-board";
|
||||
import DashboardSidebar from "./dashboard";
|
||||
import styles from "@/components/workspace/workspace.module.css";
|
||||
|
||||
/** 当前board信息由ActiveBoardProvider跨侧栏/画布共享;Suspense只包侧栏,fallback保留其布局宽度。 */
|
||||
/** 当前board信息由ActiveBoardProvider跨侧栏/画布共享;Suspense只包侧栏,fallback保留其布局宽度。
|
||||
* 该边界响应侧栏渲染期间的 suspend,不自动等待侧栏在 effect 中发起的普通请求。 */
|
||||
export default function DashboardLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<ActiveBoardProvider>
|
||||
|
||||
+2
-1
@@ -22,7 +22,8 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
/** 服务端布局输出中文html/body壳;客户端反馈Provider包在runtime宿主外侧,供宿主状态提示使用。 */
|
||||
/** 服务端布局输出中文html/body壳;客户端反馈Provider包在runtime宿主外侧,供宿主状态提示使用。
|
||||
* children 作为插槽传入客户端宿主,不会因此把所有子页面模块变成客户端代码;宿主的释放逻辑在自身模块。 */
|
||||
export default function RootLayout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="zh-CN" data-scroll-behavior="smooth">
|
||||
|
||||
@@ -35,6 +35,7 @@ export default function Login() {
|
||||
verify = hash.get("verify_email"),
|
||||
failure = hash.get("error");
|
||||
if (!code && !verify && !failure) return;
|
||||
// 不只删除认证片段,也删除原 query;当前页面没有保留/恢复任意 returnTo 的流程。
|
||||
history.replaceState(null, "", location.pathname);
|
||||
if (failure) {
|
||||
setError("第三方登录未完成,请重新尝试。");
|
||||
@@ -68,6 +69,7 @@ export default function Login() {
|
||||
* HTML输入限制给即时反馈,服务端仍负责真实凭证/注册校验。 */
|
||||
async function submit(e: FormEvent) {
|
||||
e.preventDefault();
|
||||
// busy 是显示状态,不是函数入口互斥锁;按钮禁用限制常规点击,submit 本身不检查已在执行。
|
||||
setBusy(true);
|
||||
setError("");
|
||||
setMessage("");
|
||||
@@ -76,6 +78,7 @@ export default function Login() {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
// 使用触发本次提交时 render 闭包里的 register;等待期间切换模式不会改变这次请求的后续分支。
|
||||
if (register)
|
||||
setMessage("验证邮件已请求发送,请检查邮箱并点击验证链接。");
|
||||
else router.push("/dashboard");
|
||||
@@ -98,6 +101,7 @@ export default function Login() {
|
||||
setError("无法启动登录,请重新尝试。");
|
||||
}
|
||||
}
|
||||
// submit/oauth 同样没有卸载取消或结果代次校验;回调链结束前可继续调用 router/setState。
|
||||
// 模式切换只清提示,已有邮箱/密码和可见性独立保留。
|
||||
// 渲染分为品牌故事、模式切换、受控凭证表单、OAuth按钮与demo入口;错误用alert,非错误提示用status。
|
||||
return (
|
||||
|
||||
@@ -21,12 +21,14 @@ export default async function Home() {
|
||||
signal: AbortSignal.timeout(15000),
|
||||
});
|
||||
// 按响应状态确定是否已认证,再丢弃不需要的body;此处不解析profile字段。
|
||||
// 先保存 HTTP 成功判定;随后 cancel 若抛错,catch 不会把 authenticated 重置为 false。
|
||||
authenticated = response.ok;
|
||||
await response.body?.cancel();
|
||||
} catch {
|
||||
// An unverified session must not hide the public landing page.
|
||||
}
|
||||
}
|
||||
// redirect 放在上方 try/catch 外,避免把框架用于导航的控制流异常当作 profile 请求失败吞掉。
|
||||
// 仅在确认成功后跳工作台,未认证时沿用同一静态展示组件。
|
||||
if (authenticated) redirect("/dashboard");
|
||||
return <LandingPage />;
|
||||
|
||||
Reference in New Issue
Block a user