React类组件componentDidMount与按钮触发Web3 MetaMask连接行为差异问题
报错成因
这个错误是React类组件中典型的this指向丢失问题:
- 直接在按钮的
onClick事件里绑定普通声明的loginWithEth方法时,方法执行时的this不会指向当前组件实例,而是指向undefined(严格模式下),所以访问this.state就会抛出“Cannot read properties of undefined (reading 'state')”的错误。 - 你之前在
componentDidMount里写的代码不会有这个问题,是因为React类组件的生命周期钩子默认this是绑定到组件实例的。
修复方案(任选其一即可)
方案1:在构造函数中提前绑定this
在组件的constructor里手动把方法的this绑定到当前实例:
class WalletAuth extends React.Component { constructor(props) { super(props); this.state = { // 你的原有state定义,包括web3实例 }; // 新增这行绑定this this.loginWithEth = this.loginWithEth.bind(this); } // 原有loginWithEth方法保持不变 async loginWithEth() { // 原有逻辑 } render() { // 按钮绑定可以直接写 return <button onClick={this.loginWithEth}>连接MetaMask钱包</button> } }
方案2:事件绑定时用箭头函数包裹调用
直接在onClick绑定处用箭头函数,箭头函数会继承外层作用域的this(也就是组件实例):
render() { // 此处用箭头函数包裹调用 return <button onClick={() => this.loginWithEth()}>连接MetaMask钱包</button> }
注意:这种写法每次渲染都会生成新的函数实例,性能影响极小,普通业务场景可以忽略,如果组件是高频渲染的复杂组件推荐用方案1或者方案3。
方案3:把方法定义为类属性箭头函数
直接用类属性语法定义loginWithEth为箭头函数,天然绑定当前组件实例的this:
// 把方法声明改成箭头函数形式 async loginWithEth = () => { let adr = null; try { adr = await this.state.web3.eth.requestAccounts(); this.setState({ address: adr[0] }); } catch (e) { if (e.code === 4001) { console.log('Please connect to wallet.'); } else { console.error(e.message); } } } // 绑定时直接用即可 render() { return <button onClick={this.loginWithEth}>连接MetaMask钱包</button> }
注意:类属性语法属于ES next特性,需要你的项目babel配置支持@babel/plugin-proposal-class-properties,现在主流的React脚手架(Create React App、Vite等)默认都支持该语法。
内容的提问来源于stack exchange,提问作者sebastiansieber
相关产品推荐
相关产品推荐

