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

如何在React.js中监听Solidity智能合约的登录事件?

解决React中监听Solidity登录事件的问题

首先,你的Solidity合约代码逻辑是没问题的,事件定义和触发都正确,问题出在前端React的事件监听方式上——你提到的watch()函数确实不适合用来监听合约事件,它更多是用于追踪合约状态变量的变化。下面我给你两种可靠的监听方案,基于常用的ethers.js库(v6版本,当前主流版本):

方案一:持续监听所有登录事件

如果你需要实时监听合约上所有用户的登录结果,可以用contract.on()方法来订阅事件,这会持续监听直到你主动取消订阅。

代码示例

import { useEffect, useState } from 'react';
import { ethers } from 'ethers';

// 假设你已经通过provider和abi获取了合约实例contract

function LoginComponent() {
  const [loginResult, setLoginResult] = useState(null);
  const [password, setPassword] = useState('');

  useEffect(() => {
    // 订阅LoginSuccessful事件
    const eventListener = contract.on("LoginSuccessful", (success) => {
      console.log(`登录结果:${success}`);
      // 更新React状态,用于UI展示
      setLoginResult(success);
    });

    // 组件卸载时取消订阅,避免内存泄漏
    return () => {
      eventListener.remove();
    };
  }, [contract]);

  // 登录按钮的点击事件
  const handleLogin = async () => {
    try {
      // 发送登录交易
      await contract.Login(password);
    } catch (err) {
      console.error("登录请求失败:", err);
    }
  };

  return (
    <div>
      <input 
        type="password" 
        value={password}
        onChange={(e) => setPassword(e.target.value)} 
        placeholder="输入密码"
      />
      <button onClick={handleLogin}>登录</button>
      {loginResult !== null && (
        <p className={loginResult ? "text-green" : "text-red"}>
          {loginResult ? "登录成功!" : "密码错误,请重试"}
        </p>
      )}
    </div>
  );
}

方案二:监听单次登录交易的事件

如果你只关心当前用户这次登录的结果,可以在发送交易后等待交易收据,直接从收据中提取事件数据,这种方式更精准,不需要持续监听。

代码示例

const handleLogin = async (password) => {
  try {
    // 发送登录交易并等待回执
    const tx = await contract.Login(password);
    const receipt = await tx.wait();

    // 从交易回执中筛选出LoginSuccessful事件
    const loginEvent = receipt.logs.find(log => log.fragment.name === "LoginSuccessful");
    
    if (loginEvent) {
      const success = loginEvent.args[0];
      console.log("本次登录结果:", success);
      // 更新UI状态
      setLoginResult(success);
    }
  } catch (err) {
    console.error("登录失败:", err);
  }
};

关键注意事项

  1. ethers版本适配:如果你的项目用的是ethers.js v5,API会略有不同,比如监听事件要用contract.events.LoginSuccessful(),但建议升级到v6以获得更简洁的API。
  2. 合约实例正确性:确保你的合约实例已经正确连接了用户的signer(因为Login函数需要用用户地址发送交易),否则交易无法触发针对msg.sender的密码验证。
  3. 事件名称大小写:前端监听的事件名称必须和合约中定义的完全一致(比如LoginSuccessful不能写成loginSuccessful)。

额外安全建议

你的合约已经用了keccak256哈希存储密码,这很好,但可以进一步优化安全性:存储密码时加入用户地址作为盐,避免彩虹表攻击:

// 存储密码时
users[msg.sender].password = keccak256(abi.encodePacked(_password, msg.sender));

// 验证密码时
if(users[msg.sender].password == keccak256(abi.encodePacked(_password, msg.sender))) {
  emit LoginSuccessful(true);
} else {
  emit LoginSuccessful(false);
}

内容的提问来源于stack exchange,提问作者Guna Shekar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:09:11