📝 docs(code-reader): React 钩子卡片原型改成统一的钩子卡片加扩展行
This commit is contained in:
1 parent
adf62a7706
commit
6fa06723e9
4 files changed
+10403
-2140
No files matched your search
Binary file not shown.
|
Before Width: | Height: | Size: 418 KiB After Width: | Height: | Size: 469 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 930 KiB After Width: | Height: | Size: 1.2 MiB |
+283
-169
@@ -1,7 +1,9 @@
|
||||
// 代码阅读 React 钩子卡片:一个 VS Code 窗口里左边是编辑器、右边是代码阅读预览,每张卡片和它那段源码的第一行对齐,
|
||||
// 卡片比源码高时,编辑器在那段源码下面留空,下一段源码再和下一张卡片对齐。
|
||||
// 每处钩子调用都是同一种「钩子」卡片:钩子 / 类型参数 / 参数 / 返回四行照钩子签名排,各类钩子只在后面追加自己的行,
|
||||
// 描边、图标按 React 类型定义里钩子的分组取。
|
||||
// 样例源码 `src/chat/Panel.tsx` 是手写的,两张画板共用:一张画第 1–20 行,一张画第 22–58 行。
|
||||
// 颜色、窗口和卡片画法取自同目录 react.js(VS Code Dark Modern,卡片淡底 7%、描边 35%);
|
||||
// 颜色、窗口和卡片画法取自同目录 react.js(VS Code Dark Modern,卡片淡底 7%、描边 35%),函数小框取自同目录 rust-chain.js;
|
||||
// 卡片里的译文照 vscode/src/codeReader/translators/typescriptZh.ts 的中文直译,渲染大纲的说法照 vscode/src/codeReader/rules/react.ts。
|
||||
// OpenPencil 自动折行量不准,长文字按估出的宽度手动断行,文字框都按内容长。
|
||||
|
||||
@@ -44,19 +46,13 @@ const C = {
|
||||
// 编辑器的括号配对着色(Dark Modern 的 editorBracketHighlight.foreground1–3),按嵌套层数轮换
|
||||
const BRACKETS = ["#ffd700", "#da70d6", "#179fff"];
|
||||
|
||||
// 卡片种类:上下文、自定义钩子、回调函数是这次新加的,别的同 react.js;函数同 build.js
|
||||
// 定义处的卡片种类:上下文、自定义钩子是这次新加的,别的同 react.js;函数同 build.js。钩子调用的卡片按分类取色,见 HOOK
|
||||
const K = {
|
||||
import: { label: "导入", color: "#c586c0", icon: "import" },
|
||||
fn: { label: "函数", color: "#dcdcaa", icon: "square-function" },
|
||||
context: { label: "上下文", color: "#4ec9b0", icon: "share-2" },
|
||||
hook: { label: "自定义钩子", color: "#61dafb", icon: "plug" },
|
||||
component: { label: "React 组件", color: "#61dafb", icon: "atom" },
|
||||
state: { label: "状态", color: "#9cdcfe", icon: "toggle-right" },
|
||||
ref: { label: "引用", color: "#9cdcfe", icon: "anchor" },
|
||||
read: { label: "数据源", color: "#9cdcfe", icon: "download" },
|
||||
derived: { label: "派生值", color: "#9cdcfe", icon: "sigma" },
|
||||
callback: { label: "回调函数", color: "#dcdcaa", icon: "square-function" },
|
||||
effect: { label: "副作用", color: "#e5c07b", icon: "zap" },
|
||||
handler: { label: "事件处理函数", color: "#dcdcaa", icon: "mouse-pointer-click" },
|
||||
render: { label: "渲染输出", color: "#89d185", icon: "layout-template" },
|
||||
};
|
||||
@@ -642,15 +638,6 @@ function nameProp(ctx, name, color, tags, label) {
|
||||
return line;
|
||||
}
|
||||
|
||||
/** 值后面跟一个小标签(「来自 … 自定义钩子」「仅挂载时 浏览器绘制前」)。 */
|
||||
function withTag(ctx, segs, label, color, mono) {
|
||||
return (frame) => {
|
||||
const line = row(frame, "Line", { gap: 6, height: 20, width: "fit_content" });
|
||||
text(line, segs, { mono: mono !== false });
|
||||
tag(line, label, color, ctx.bg);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 表格:`cols` 是 `{name, color?, mono?}`,最后一列分剩下的;格子是着色的段、字符串(按列色)或带 `draw` 的对象。
|
||||
* 列宽按整列的内容估,表头浅底,行和列之间一条分隔线。
|
||||
@@ -739,9 +726,6 @@ function outline(parent, items, bg) {
|
||||
// ─── 卡片内容:第 1–20 行 ────────────────────────────────────────────────────
|
||||
|
||||
const EXPORTED = ["具名导出", C.keyword];
|
||||
const SESSION_EFFECT = "副作用「id 变化时」";
|
||||
const OPEN_EFFECT = "副作用「open 变化时」";
|
||||
const MOUNT_EFFECT = "副作用「仅挂载时」";
|
||||
|
||||
/** 导入收起时只剩一行:来源和导入项个数。 */
|
||||
function importCard(parent, w) {
|
||||
@@ -781,36 +765,281 @@ function hookCard(parent, w) {
|
||||
prop(ctx, "参数", px("1 个", C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "类型", color: C.type }], [["id", cx("字符串")]]);
|
||||
prop(ctx, "返回", px("1 个", C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "是什么", mono: false }], [["messages", [link("状态 messages", K.state.color)]]]);
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "是什么", mono: false }], [["messages", [link("状态 messages", HOOK.state.color)]]]);
|
||||
}
|
||||
|
||||
function messagesStateCard(parent, w) {
|
||||
const ctx = card(parent, K.state, w, { name: "messages" });
|
||||
nameProp(ctx, "messages", C.variable);
|
||||
prop(ctx, "类型", cx("Message[]"));
|
||||
prop(ctx, "初始值", cx("空数组"));
|
||||
prop(ctx, "修改函数", px("setMessages", C.fn));
|
||||
prop(ctx, "在哪改", [link(SESSION_EFFECT, K.effect.color), seg(" 里的 ", C.fg)].concat(cx("ws.onmessage")));
|
||||
// ─── 钩子调用:基础卡片加扩展行 ──────────────────────────────────────────────
|
||||
|
||||
// 钩子的分类,同 React 类型定义里钩子的分组:卡片描边、图标和钩子名后面的分类小标签按它取
|
||||
const HOOK = {
|
||||
state: { label: "状态", color: "#9cdcfe", icon: "toggle-right" },
|
||||
effect: { label: "副作用", color: "#e5c07b", icon: "zap" },
|
||||
ref: { label: "引用", color: "#9cdcfe", icon: "anchor" },
|
||||
perf: { label: "性能", color: "#9cdcfe", icon: "sigma" },
|
||||
context: { label: "上下文", color: "#4ec9b0", icon: "share-2" },
|
||||
concurrent: { label: "并发", color: "#9cdcfe", icon: "hourglass" },
|
||||
custom: { label: "自定义钩子", color: "#61dafb", icon: "plug" },
|
||||
};
|
||||
|
||||
// 所有钩子卡片同一个标签列宽,最长的标签是上下文的「没有外层提供时」
|
||||
const HOOK_LABEL_W = 100;
|
||||
|
||||
/** 依赖项的三种读法:某个值变化时、空数组的仅挂载时、没写依赖的每次渲染后。 */
|
||||
const changed = (name) => [seg(name, C.variable), seg(" 变化时", C.keyword)];
|
||||
const ON_MOUNT = [seg("仅挂载时", C.keyword)];
|
||||
const NO_DEPS = [seg("没写,", C.desc), seg("每次渲染后", C.keyword)];
|
||||
|
||||
/** 函数参数收成的小框:朝右的折叠箭头,写「函数 (参数) · N 句」,没参数时不写括号;同调用链原型的闭包小框。 */
|
||||
function fnBox(params, count) {
|
||||
const segs = [seg("函数", C.desc)]
|
||||
.concat(params ? [seg(" (", C.fg)].concat(params, [seg(")", C.fg)]) : [])
|
||||
.concat([seg(" · " + count + " 句", C.desc)]);
|
||||
return {
|
||||
est: segs.map((s) => s.text).join(""),
|
||||
draw: (frame) => {
|
||||
const pill = row(frame, "Fold box", {
|
||||
width: "fit_content",
|
||||
height: 20,
|
||||
padding: [0, 6, 0, 3],
|
||||
gap: 3,
|
||||
radius: 4,
|
||||
fill: C.input,
|
||||
stroke: C.borderStrong,
|
||||
});
|
||||
icon(pill, "chevron-right", C.desc, 13);
|
||||
text(pill, segs, { mono: true, size: 12.5, lh: 18 });
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** 副作用:触发时机、用到、改动、清理函数(有才写)一行一项,函数体收起。 */
|
||||
function effectCard(parent, w, o) {
|
||||
const ctx = card(parent, K.effect, w, { name: o.name, fold: "closed" });
|
||||
prop(ctx, "触发时机", o.trigger, { mono: o.triggerMono !== false });
|
||||
/**
|
||||
* 钩子调用的卡片,所有钩子共用一种:钩子 / 类型参数 / 参数 / 返回四行照钩子签名排,没有的行不显示,
|
||||
* `extend` 在后面追加这类钩子自己的行。描边、图标、分类小标签按 `cat` 取;`fold` 表示有函数参数,函数体子块收起。
|
||||
* `params` 每项是「参数 | 值」,`returns` 每项是「名称 | 是什么」,格子同 [table]。
|
||||
*/
|
||||
function hookCall(parent, w, h) {
|
||||
const kind = { label: "钩子", color: h.cat.color, icon: h.cat.icon };
|
||||
const ctx = card(parent, kind, w, { name: h.name + " · " + h.target, fold: h.fold ? "closed" : null, labelW: HOOK_LABEL_W });
|
||||
const line = row(ctx.content, "Prop / 钩子", { gap: 12, align: "start" });
|
||||
const key = row(line, "Key", { width: ctx.labelW, height: 20 });
|
||||
text(key, "钩子", { size: 12.5, color: C.desc, lh: 20 });
|
||||
const value = row(line, "Value", { gap: 6, height: 20 });
|
||||
text(value, [seg(h.name, C.fn, h.link ? { w: 600, u: true } : { w: 600 })], { mono: true });
|
||||
for (const [label, color] of [[h.cat.label, h.cat.color]].concat(h.tags || [])) tag(value, label, color, ctx.bg);
|
||||
if (h.typeArg)
|
||||
prop(ctx, "类型参数", cx(h.typeArg));
|
||||
if (h.params) {
|
||||
prop(ctx, "参数", px(`${h.params.length} 个`, C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "参数", color: C.variable }, { name: "值" }], h.params);
|
||||
}
|
||||
if (h.returns) {
|
||||
prop(ctx, "返回", px(`${h.returns.length} 个`, C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "是什么", mono: false }], h.returns);
|
||||
}
|
||||
if (h.extend)
|
||||
h.extend(ctx);
|
||||
}
|
||||
|
||||
/** 副作用的扩展行:用到、改动、清理函数(有才写)。 */
|
||||
function effectRows(o) {
|
||||
return (ctx) => {
|
||||
prop(ctx, "用到", o.uses);
|
||||
prop(ctx, "改动", o.changes, { mono: o.changesMono !== false });
|
||||
if (o.cleanup)
|
||||
prop(ctx, "清理函数", cx(o.cleanup));
|
||||
return ctx;
|
||||
};
|
||||
}
|
||||
|
||||
function sessionEffectCard(parent, w) {
|
||||
effectCard(parent, w, {
|
||||
name: "id 变化时",
|
||||
trigger: [seg("id", C.variable), seg(" 变化时", C.keyword)],
|
||||
uses: px("id", C.variable),
|
||||
changes: [seg("状态 ", C.fg), seg("messages", C.variable)],
|
||||
cleanup: "ws.close()",
|
||||
// ─── 钩子调用:样例里的每一处 ────────────────────────────────────────────────
|
||||
|
||||
const SESSION_EFFECT = "副作用「id 变化时」";
|
||||
const OPEN_EFFECT = "副作用「open 变化时」";
|
||||
const MOUNT_EFFECT = "副作用「仅挂载时」";
|
||||
|
||||
/** 第 13 行:自定义钩子里的 `useState`。 */
|
||||
function messagesStateHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.state,
|
||||
name: "useState",
|
||||
target: "messages",
|
||||
typeArg: "Message[]",
|
||||
params: [["initialState", cx("空数组")]],
|
||||
returns: [["messages", "当前值"], [px("setMessages", C.fn), "修改函数"]],
|
||||
extend: (ctx) => prop(ctx, "在哪改", [link(SESSION_EFFECT, HOOK.effect.color), seg(" 里的 ", C.fg)].concat(cx("ws.onmessage"))),
|
||||
});
|
||||
}
|
||||
|
||||
/** 第 14 行:自定义钩子里的 `useEffect`。 */
|
||||
function sessionEffectHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.effect,
|
||||
name: "useEffect",
|
||||
target: "id 变化时",
|
||||
fold: true,
|
||||
params: [["setup", fnBox(null, 3)], ["deps", changed("id")]],
|
||||
extend: effectRows({ uses: px("id", C.variable), changes: [seg("状态 ", C.fg), seg("messages", C.variable)], cleanup: "ws.close()" }),
|
||||
});
|
||||
}
|
||||
|
||||
function themeHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.context,
|
||||
name: "useContext",
|
||||
target: "theme",
|
||||
params: [["context", [link("ThemeContext", K.context.color)]]],
|
||||
returns: [["theme", "上下文的值"]],
|
||||
extend: (ctx) => prop(ctx, "没有外层提供时", px("'light'", C.string)),
|
||||
});
|
||||
}
|
||||
|
||||
function sessionHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.custom,
|
||||
name: "useChatSession",
|
||||
link: true,
|
||||
target: "messages",
|
||||
params: [["id", cx("id")]],
|
||||
returns: [["messages", [link("状态 messages", HOOK.state.color)]]],
|
||||
});
|
||||
}
|
||||
|
||||
function openStateHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.state,
|
||||
name: "useState",
|
||||
target: "open",
|
||||
params: [["initialState", [seg("首次渲染时调用 ", C.fg)].concat(cx("readOpen(id)"))]],
|
||||
returns: [["open", "当前值"], [px("setOpen", C.fn), "修改函数"]],
|
||||
extend: (ctx) => prop(ctx, "在哪改", [link("toggle", C.fn), seg("、", C.fg), link(OPEN_EFFECT, HOOK.effect.color)]),
|
||||
});
|
||||
}
|
||||
|
||||
function reducerHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.state,
|
||||
name: "useReducer",
|
||||
target: "state",
|
||||
params: [["reducer", [link("reducer", C.fn)]], ["initialArg", cx("{ count: 0 }")]],
|
||||
returns: [["state", "当前值"], [px("dispatch", C.fn), "派发函数"]],
|
||||
extend: (ctx) => {
|
||||
prop(ctx, "动作", "", { fold: "open" });
|
||||
table(ctx, [{ name: "动作", color: C.string }, { name: "状态怎么变" }], [
|
||||
["'add'", [seg("count", C.variable), seg(" 加 ", C.fg), seg("1", C.number)]],
|
||||
[px("其他", C.desc), px("不变", C.fg)],
|
||||
]);
|
||||
prop(ctx, "在哪派发", [link("toggle", C.fn), seg("(", C.fg), seg("'add'", C.string), seg(")", C.fg)]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function transitionHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.concurrent,
|
||||
name: "useTransition",
|
||||
target: "isPending",
|
||||
returns: [["isPending", "是否正在过渡"], [px("startTransition", C.fn), "启动过渡的函数"]],
|
||||
});
|
||||
}
|
||||
|
||||
function boxRefHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.ref,
|
||||
name: "useRef",
|
||||
target: "boxRef",
|
||||
typeArg: "HTMLDivElement",
|
||||
params: [["initialValue", cx("空")]],
|
||||
returns: [["boxRef", "引用对象"]],
|
||||
extend: (ctx) => {
|
||||
prop(ctx, "指向", [seg("<div>", C.nativeTag), seg(" 元素", C.fg)]);
|
||||
prop(ctx, "用在", [seg("<div>", C.nativeTag), seg(" 的 ref 属性、", C.fg), link(MOUNT_EFFECT, HOOK.effect.color)]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function timerHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.ref,
|
||||
name: "useRef",
|
||||
target: "timer",
|
||||
typeArg: "数值",
|
||||
params: [["initialValue", [seg("没写,", C.desc), seg("未定义", C.number)]]],
|
||||
returns: [["timer", "引用对象"]],
|
||||
extend: (ctx) => {
|
||||
prop(ctx, "写入", [link(OPEN_EFFECT, HOOK.effect.color)]);
|
||||
prop(ctx, "读取", [link(OPEN_EFFECT, HOOK.effect.color), seg(" 的清理函数", C.fg)]);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function totalHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.perf,
|
||||
name: "useMemo",
|
||||
target: "total",
|
||||
fold: true,
|
||||
params: [["factory", fnBox(null, 2)], ["deps", changed("messages")]],
|
||||
returns: [["total", "算出的值"]],
|
||||
extend: (ctx) => prop(ctx, "算出", (frame, vw) => {
|
||||
text(frame, cx("sum * 2"), { mono: true, maxW: vw });
|
||||
text(frame, "其中 sum = messages.length", { mono: true, size: 12.5, color: C.desc, maxW: vw });
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function toggleHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.perf,
|
||||
name: "useCallback",
|
||||
target: "toggle",
|
||||
fold: true,
|
||||
params: [["callback", fnBox([seg("next", C.variable), seg(": ", C.fg), seg("布尔", C.type)], 2)], ["deps", ON_MOUNT]],
|
||||
returns: [[px("toggle", C.fn), "记住的函数"]],
|
||||
extend: (ctx) => prop(ctx, "调用位置", [link("handleClick", C.fn)]),
|
||||
});
|
||||
}
|
||||
|
||||
function openEffectHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.effect,
|
||||
name: "useEffect",
|
||||
target: "open 变化时",
|
||||
fold: true,
|
||||
params: [["setup", fnBox(null, 2)], ["deps", changed("open")]],
|
||||
extend: effectRows({
|
||||
uses: [seg("open", C.variable), seg("、", C.fg), seg("timer", C.variable)],
|
||||
changes: [
|
||||
seg("状态 ", C.fg),
|
||||
seg("open", C.variable),
|
||||
seg("(1 秒后设为 ", C.fg),
|
||||
seg("假", C.number),
|
||||
seg(")、引用 ", C.fg),
|
||||
seg("timer", C.variable),
|
||||
],
|
||||
cleanup: "clearTimeout(timer.current)",
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function renderEffectHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.effect,
|
||||
name: "useEffect",
|
||||
target: "每次渲染后",
|
||||
fold: true,
|
||||
params: [["setup", fnBox(null, 1)], ["deps", NO_DEPS]],
|
||||
extend: effectRows({ uses: px("total", C.variable), changes: cx("document.title") }),
|
||||
});
|
||||
}
|
||||
|
||||
function layoutEffectHook(parent, w) {
|
||||
hookCall(parent, w, {
|
||||
cat: HOOK.effect,
|
||||
name: "useLayoutEffect",
|
||||
target: "仅挂载时",
|
||||
tags: [["浏览器绘制前", HOOK.effect.color]],
|
||||
fold: true,
|
||||
params: [["setup", fnBox(null, 1)], ["deps", ON_MOUNT]],
|
||||
extend: effectRows({ uses: [link("boxRef", C.variable)], changes: px("无", C.desc), changesMono: false }),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -850,121 +1079,6 @@ function panelCard(parent, w) {
|
||||
]);
|
||||
}
|
||||
|
||||
function themeCard(parent, w) {
|
||||
const ctx = card(parent, K.read, w, { name: "theme", labelW: 100 });
|
||||
nameProp(ctx, "theme", C.variable, [], "变量");
|
||||
prop(ctx, "来自", [seg("上下文 ", C.fg), link("ThemeContext", K.context.color)]);
|
||||
prop(ctx, "没有外层提供时", px("'light'", C.string));
|
||||
}
|
||||
|
||||
function messagesReadCard(parent, w) {
|
||||
const ctx = card(parent, K.read, w, { name: "messages" });
|
||||
nameProp(ctx, "messages", C.variable, [], "取出");
|
||||
prop(ctx, "来自", withTag(ctx, [link("useChatSession", C.fn)].concat(cx("(id)")), "自定义钩子", K.hook.color));
|
||||
}
|
||||
|
||||
function openStateCard(parent, w) {
|
||||
const ctx = card(parent, K.state, w, { name: "open" });
|
||||
nameProp(ctx, "open", C.variable);
|
||||
prop(ctx, "初始值", [seg("首次渲染时调用 ", C.fg)].concat(cx("readOpen(id)")));
|
||||
prop(ctx, "修改函数", px("setOpen", C.fn));
|
||||
prop(ctx, "在哪改", [link("toggle", C.fn), seg("、", C.fg), link(OPEN_EFFECT, K.effect.color)]);
|
||||
}
|
||||
|
||||
function reducerStateCard(parent, w) {
|
||||
const ctx = card(parent, K.state, w, { name: "state" });
|
||||
nameProp(ctx, "state", C.variable, [["useReducer", K.state.color]]);
|
||||
prop(ctx, "初始值", cx("{ count: 0 }"));
|
||||
prop(ctx, "派发函数", px("dispatch", C.fn));
|
||||
prop(ctx, "处理函数", [link("reducer", C.fn)]);
|
||||
prop(ctx, "动作", "", { fold: "open" });
|
||||
table(ctx, [{ name: "动作", color: C.string }, { name: "状态怎么变" }], [
|
||||
["'add'", [seg("count", C.variable), seg(" 加 ", C.fg), seg("1", C.number)]],
|
||||
[px("其他", C.desc), px("不变", C.fg)],
|
||||
]);
|
||||
prop(ctx, "在哪派发", [link("toggle", C.fn), seg("(", C.fg), seg("'add'", C.string), seg(")", C.fg)]);
|
||||
}
|
||||
|
||||
function transitionCard(parent, w) {
|
||||
const ctx = card(parent, K.read, w, { name: "isPending, startTransition" });
|
||||
prop(ctx, "取出", px("2 个", C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "是什么", mono: false }], [
|
||||
["isPending", "是否正在过渡"],
|
||||
[px("startTransition", C.fn), "启动过渡的函数"],
|
||||
]);
|
||||
prop(ctx, "来自", withTag(ctx, cx("useTransition()"), "React", C.component));
|
||||
}
|
||||
|
||||
function boxRefCard(parent, w) {
|
||||
const ctx = card(parent, K.ref, w, { name: "boxRef" });
|
||||
nameProp(ctx, "boxRef", C.variable, [["元素", K.ref.color]]);
|
||||
prop(ctx, "指向", [seg("<div>", C.nativeTag), seg(" 元素(", C.fg), seg("HTMLDivElement", C.type), seg(")", C.fg)]);
|
||||
prop(ctx, "初始值", cx("空"));
|
||||
prop(ctx, "用在", [seg("<div>", C.nativeTag), seg(" 的 ref 属性;", C.fg), link(MOUNT_EFFECT, K.effect.color)]);
|
||||
}
|
||||
|
||||
function timerCard(parent, w) {
|
||||
const ctx = card(parent, K.ref, w, { name: "timer" });
|
||||
nameProp(ctx, "timer", C.variable, [["可变值,改了不重新渲染", K.ref.color]]);
|
||||
prop(ctx, "存的类型", cx("数值"));
|
||||
prop(ctx, "初始值", cx("未定义"));
|
||||
prop(ctx, "写入", [link(OPEN_EFFECT, K.effect.color)]);
|
||||
prop(ctx, "读取", [link(OPEN_EFFECT, K.effect.color), seg(" 的清理函数", C.fg)]);
|
||||
}
|
||||
|
||||
function totalCard(parent, w) {
|
||||
const ctx = card(parent, K.derived, w, { name: "total", fold: "closed" });
|
||||
nameProp(ctx, "total", C.variable);
|
||||
prop(ctx, "计算", (frame, vw) => {
|
||||
text(frame, cx("sum * 2"), { mono: true, maxW: vw });
|
||||
text(frame, "其中 sum = messages.length", { mono: true, size: 12.5, color: C.desc, maxW: vw });
|
||||
});
|
||||
prop(ctx, "重算时机", [seg("messages", C.variable), seg(" 变化时", C.keyword)]);
|
||||
}
|
||||
|
||||
function toggleCard(parent, w) {
|
||||
const ctx = card(parent, K.callback, w, { name: "toggle", fold: "closed" });
|
||||
nameProp(ctx, "toggle", C.fn, [["记忆化", K.callback.color]]);
|
||||
prop(ctx, "参数", px("1 个", C.desc), { mono: false, fold: "open" });
|
||||
table(ctx, [{ name: "名称", color: C.variable }, { name: "类型", color: C.type }], [["next", cx("布尔")]]);
|
||||
prop(ctx, "调用位置", [link("handleClick", C.fn)]);
|
||||
prop(ctx, "重建时机", [seg("不重建", C.keyword), seg("(依赖为空)", C.desc)], { mono: false });
|
||||
}
|
||||
|
||||
function openEffectCard(parent, w) {
|
||||
effectCard(parent, w, {
|
||||
name: "open 变化时",
|
||||
trigger: [seg("open", C.variable), seg(" 变化时", C.keyword)],
|
||||
uses: [seg("open", C.variable), seg("、", C.fg), seg("timer", C.variable)],
|
||||
changes: [
|
||||
seg("状态 ", C.fg),
|
||||
seg("open", C.variable),
|
||||
seg("(1 秒后设为 ", C.fg),
|
||||
seg("假", C.number),
|
||||
seg(")、引用 ", C.fg),
|
||||
seg("timer", C.variable),
|
||||
],
|
||||
cleanup: "clearTimeout(timer.current)",
|
||||
});
|
||||
}
|
||||
|
||||
function renderEffectCard(parent, w) {
|
||||
effectCard(parent, w, {
|
||||
name: "每次渲染后",
|
||||
trigger: px("每次渲染后", C.keyword),
|
||||
triggerMono: false,
|
||||
uses: px("total", C.variable),
|
||||
changes: cx("document.title"),
|
||||
});
|
||||
}
|
||||
|
||||
function layoutEffectCard(parent, w) {
|
||||
const ctx = card(parent, K.effect, w, { name: "仅挂载时", fold: "closed" });
|
||||
prop(ctx, "触发时机", withTag(ctx, px("仅挂载时", C.keyword), "浏览器绘制前", K.effect.color, false));
|
||||
prop(ctx, "用到", [link("boxRef", C.variable)]);
|
||||
prop(ctx, "改动", px("无", C.desc), { mono: false });
|
||||
}
|
||||
|
||||
function handleClickCard(parent, w) {
|
||||
const ctx = card(parent, K.handler, w, { name: "handleClick", fold: "closed" });
|
||||
nameProp(ctx, "handleClick", C.fn);
|
||||
@@ -1158,25 +1272,25 @@ windowOf("Prototype / React 钩子 · 自定义钩子与上下文", 0, [
|
||||
{ from: 3, to: 4, draw: contextCard },
|
||||
{ from: 5, to: 11, draw: reducerCard },
|
||||
{ from: 12, to: 12, draw: hookCard },
|
||||
{ from: 13, to: 13, depth: 1, draw: messagesStateCard },
|
||||
{ from: 14, to: 18, depth: 1, last: true, draw: sessionEffectCard },
|
||||
{ from: 13, to: 13, depth: 1, draw: messagesStateHook },
|
||||
{ from: 14, to: 18, depth: 1, last: true, draw: sessionEffectHook },
|
||||
{ from: 19, to: 20 },
|
||||
]);
|
||||
|
||||
windowOf("Prototype / React 钩子 · 组件 Panel", WIN_W + BOARD_GAP, [
|
||||
{ from: 22, to: 22, draw: panelCard },
|
||||
{ from: 23, to: 23, depth: 1, draw: themeCard },
|
||||
{ from: 24, to: 24, depth: 1, draw: messagesReadCard },
|
||||
{ from: 25, to: 25, depth: 1, draw: openStateCard },
|
||||
{ from: 26, to: 26, depth: 1, draw: reducerStateCard },
|
||||
{ from: 27, to: 27, depth: 1, draw: transitionCard },
|
||||
{ from: 28, to: 28, depth: 1, draw: boxRefCard },
|
||||
{ from: 29, to: 29, depth: 1, draw: timerCard },
|
||||
{ from: 30, to: 33, depth: 1, draw: totalCard },
|
||||
{ from: 34, to: 37, depth: 1, draw: toggleCard },
|
||||
{ from: 38, to: 41, depth: 1, draw: openEffectCard },
|
||||
{ from: 42, to: 44, depth: 1, draw: renderEffectCard },
|
||||
{ from: 45, to: 47, depth: 1, draw: layoutEffectCard },
|
||||
{ from: 23, to: 23, depth: 1, draw: themeHook },
|
||||
{ from: 24, to: 24, depth: 1, draw: sessionHook },
|
||||
{ from: 25, to: 25, depth: 1, draw: openStateHook },
|
||||
{ from: 26, to: 26, depth: 1, draw: reducerHook },
|
||||
{ from: 27, to: 27, depth: 1, draw: transitionHook },
|
||||
{ from: 28, to: 28, depth: 1, draw: boxRefHook },
|
||||
{ from: 29, to: 29, depth: 1, draw: timerHook },
|
||||
{ from: 30, to: 33, depth: 1, draw: totalHook },
|
||||
{ from: 34, to: 37, depth: 1, draw: toggleHook },
|
||||
{ from: 38, to: 41, depth: 1, draw: openEffectHook },
|
||||
{ from: 42, to: 44, depth: 1, draw: renderEffectHook },
|
||||
{ from: 45, to: 47, depth: 1, draw: layoutEffectHook },
|
||||
{ from: 48, to: 50, depth: 1, draw: handleClickCard },
|
||||
{ from: 51, to: 57, depth: 1, last: true, draw: renderCard },
|
||||
{ from: 58, to: 58 },
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user