You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 12:21:03