From 50e64cd34cf855ddd983132a4bf1a676ff2577d7 Mon Sep 17 00:00:00 2001 From: xfy Date: Wed, 15 Jul 2026 10:29:01 +0800 Subject: [PATCH] =?UTF-8?q?fix(code=5Frunner):=20use=5Fresolved=5Ftheme=20?= =?UTF-8?q?=E4=BB=8E=20use=5Feffect=20=E9=97=AD=E5=8C=85=E6=8F=90=E5=88=B0?= =?UTF-8?q?=20cfg=20=E5=9D=97=E9=A1=B6=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dx check 报 4 处 'hook called in a closure: use_resolved_theme': use_resolved_theme() 是 hook(内部 use_context),被错误地放在 use_effect 的 move || { ... } 闭包内调用。Dioxus 规则要求 hook 只能在组件渲染路径顶层调用。 修复:在两个 #[cfg(target_arch="wasm32")] 块顶层各调用一次 use_resolved_theme() 拿到 Memo,move 进下方 effect 闭包;闭包内改为调用 memo (resolved_theme())读值。调用 memo 本身不是 hook(Memo 是 Copy + Fn), 读值的同时建立主题订阅——主题切换时 effect 仍会重跑,行为不变。 范式对齐 ThemeToggle(src/theme.rs:341)的正确用法。 影响 4 处:CodeMirror 挂载/主题同步 effect、xterm 挂载/主题同步 effect。 --- src/components/code_runner/runner.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/components/code_runner/runner.rs b/src/components/code_runner/runner.rs index 204c7d7..3568830 100644 --- a/src/components/code_runner/runner.rs +++ b/src/components/code_runner/runner.rs @@ -126,6 +126,10 @@ pub fn CodeRunner( let mut editor_handle: Signal> = use_signal(|| None); + // 在 cfg 块顶层(渲染路径)取主题 memo,move 进下方 effect 闭包;闭包内只 + // 调用 memo(resolved())读值——调用 memo 本身不是 hook,use_resolved_theme + // 这个 hook 必须在组件体顶层调用,不能放进 use_effect 闭包(dx check 会报)。 + let resolved_theme = use_resolved_theme(); // 首次挂载:构造 closure + options,create 后存进 editor_handle。 // 用 resolved() 读取主题作为初始值(同时订阅,但主题切换由下方独立 effect 处理)。 @@ -146,8 +150,7 @@ pub fn CodeRunner( // 但 EditorHandle 签名要求该闭包,传 no-op 满足生命周期。 let on_run_shortcut = Closure::new(|| {}); - let resolved = use_resolved_theme(); - let theme_name = if resolved() == ResolvedTheme::Dark { + let theme_name = if resolved_theme() == ResolvedTheme::Dark { "dark" } else { "light" @@ -186,7 +189,6 @@ pub fn CodeRunner( // 期间跳过,让 VT 事件负责换肤;动画结束后此 effect 会因 resolved 信号变化重跑 // (此时 is-theme-transitioning 已移除),做一次幂等的兜底同步。 use_effect(move || { - let r = use_resolved_theme(); #[cfg(target_arch = "wasm32")] { let transitioning = web_sys::window() @@ -200,7 +202,7 @@ pub fn CodeRunner( } if let Some(h) = editor_handle.read().as_ref() { h.instance() - .set_theme(if r() == ResolvedTheme::Dark { + .set_theme(if resolved_theme() == ResolvedTheme::Dark { "dark" } else { "light" @@ -242,6 +244,10 @@ pub fn CodeRunner( use crate::xterm_bridge; use wasm_bindgen::closure::Closure; + // 在 cfg 块顶层(渲染路径)取主题 memo,move 进下方 effect 闭包;闭包内只 + // 调用 memo(resolved_theme())读值——调用 memo 本身不是 hook。 + let resolved_theme = use_resolved_theme(); + // 首次挂载:构造 onReady 闭包 + XtermOptions,create 后存进 term_handle。 // 订阅 show_output:输出区在 show_output 变 true(用户点运行)后才渲染进 DOM, // 容器此前不存在;读 show_output 建立订阅,使其变 true 时重跑本 effect 完成挂载。 @@ -255,8 +261,7 @@ pub fn CodeRunner( } let on_ready = Closure::new(|| {}); - let resolved = use_resolved_theme(); - let theme_name = if resolved() == ResolvedTheme::Dark { + let theme_name = if resolved_theme() == ResolvedTheme::Dark { "dark" } else { "light" @@ -278,7 +283,6 @@ pub fn CodeRunner( // 主题切换时同步终端主题。 // VT 动画期间跳过(同 CodeMirror 的 use_effect,见上方注释)。 use_effect(move || { - let r = use_resolved_theme(); #[cfg(target_arch = "wasm32")] { let transitioning = web_sys::window() @@ -292,7 +296,7 @@ pub fn CodeRunner( } if let Some(h) = term_handle.read().as_ref() { h.instance() - .set_theme(if r() == ResolvedTheme::Dark { + .set_theme(if resolved_theme() == ResolvedTheme::Dark { "dark" } else { "light"