如何在use_effect钩子中调用使用Yewdux Store的可复用Hook?
解决Yew中在use_effect里调用自定义Hook的问题
问题根源
Hook规则明确要求:只能在组件函数或自定义Hook的顶层调用Hook,不能在use_effect闭包、条件分支、循环等嵌套结构里调用——这会破坏Hook调用顺序的一致性,导致状态管理异常。你原代码里尝试在use_effect的异步闭包里调用use_sign_tx,直接违反了这个规则。
解决方案:调整Hook设计,适配规则
下面两种改造方式,既能遵守Hook规则,又能实现你要的功能:
方案一:让Hook监听触发条件,自动执行逻辑
修改use_sign_tx,让它接收触发信号(比如首次加载状态),在Hook内部用use_effect执行异步逻辑,组件只需在顶层调用Hook即可。
use crate::components::accounts::account_store::PhraseStore; use yew::prelude::*; use yewdux::prelude::*; #[hook] pub fn use_sign_tx<T>(tx: T, trigger: bool) where T: 'static + Clone, { let (store, _) = use_store::<PhraseStore>(); let tx_clone = tx.clone(); // Hook内部用use_effect监听触发条件 use_effect_with_deps( move |&trigger| { if trigger { wasm_bindgen_futures::spawn_local(async move { // 在这里写你的签名逻辑,使用store和tx_clone // 示例:let result = sign_transaction(store.phrase.clone(), tx_clone).await; }); } || {} }, trigger, ); } // 组件调用示例 #[function_component(TransactionFromHooks)] pub fn transaction() -> Html { let first_load = use_state(|| true); // 假设这里是你的交易数据,可从props或状态获取 let tx = /* 你的交易对象 */; // 在组件顶层调用自定义Hook,传递交易数据和触发条件 use_sign_tx(tx, *first_load); // 首次加载后重置触发状态 use_effect(move || { if *first_load { first_load.set(false); } || {} }); html! { <h1>{"Transaction"}</h1> } }
方案二:让Hook返回可执行的异步函数,在use_effect里调用
如果想更灵活控制执行时机,可以让use_sign_tx返回一个异步函数,组件在顶层调用Hook拿到函数后,再在use_effect里执行它。
use crate::components::accounts::account_store::PhraseStore; use yew::prelude::*; use yewdux::prelude::*; #[hook] pub fn use_sign_tx<T>(tx: T) -> impl Fn() + 'static where T: 'static + Clone, { let (store, _) = use_store::<PhraseStore>(); let tx_clone = tx.clone(); // 返回包含异步逻辑的闭包 move || { wasm_bindgen_futures::spawn_local(async move { // 执行签名逻辑,使用store和tx_clone // 示例:let result = sign_transaction(store.phrase.clone(), tx_clone).await; }); } } // 组件调用示例 #[function_component(TransactionFromHooks)] pub fn transaction() -> Html { let first_load = use_state(|| true); let tx = /* 你的交易对象 */; // 在组件顶层调用Hook,拿到执行函数 let sign_tx_fn = use_sign_tx(tx); use_effect(move || { if *first_load { // 调用从Hook拿到的函数 sign_tx_fn(); first_load.set(false); } || {} }); html! { <h1>{"Transaction"}</h1> } }
关键注意事项
- 所有Hook调用必须放在组件函数的顶层,不能嵌套在任何闭包或条件判断里。
- 传递给异步逻辑的变量要正确克隆(异步闭包会捕获变量所有权),同时要满足Yew异步逻辑要求的
'static生命周期约束。
内容的提问来源于stack exchange,提问作者Amiya Behera
相关产品推荐
相关产品推荐

