我正在使用web3-react,我不知道如何在浏览器刷新时保持与MetaMask钱包的连接。
这是代码:
// define the injectedConnectors
const injectedConnector = new InjectedConnector({
supportedChainIds: [
1, // Mainet
3, // Ropsten
4, // Rinkeby
5, // Goerli
42, // Kovan
],
})
const { chainId, account, activate, active } = useWeb3React()
// activate the wallet
activate(injectedConnector)
console.log(account)
// all good.
到目前为止,一切都在工作,我激活了我的MetaMask钱包,并正确记录了账户,活动变量是一个变为true的布尔值。
问题是,当我刷新页面时,活动变为false,并且我失去了UI与MetaMask钱包之间的连接。当然,将活动保存到浏览器中不会改变任何内容,因为连接依赖于活动布尔值。
这些文件缺少这样的信息。
终于找到了解决方案!我试着用官方图书馆的例子。。。但由于某种原因,虽然没有出现任何错误,但它还是不起作用。然后我偶然发现了一个有同样问题的人,他在reddit上发帖,得到了一个对我有用的好答案。这是帖子的链接:https://www.reddit.com/r/ethdev/comments/nw7iyv/displaying_connected_wallet_after_browser_refresh/h5uxl88/?context=3这是那篇文章的代码:
首先创建一个文件,其中包含名为connectors.js:的注入连接器
import { InjectedConnector } from '@web3-react/injected-connector'
export const Injected = new InjectedConnector({ supportedNetworks: [1, 3, 4, 5, 42] })
然后创建一个组件来检查用户是否已经激活了钱包:
import React, { useEffect, useState } from 'react'
import { injected } from '../connectors'
import { useWeb3React } from '@web3-react/core'
function MetamaskProvider({ children }) {
const { active: networkActive, error: networkError, activate: activateNetwork } = useWeb3React()
const [loaded, setLoaded] = useState(false)
useEffect(() => {
injected
.isAuthorized()
.then((isAuthorized) => {
setLoaded(true)
if (isAuthorized && !networkActive && !networkError) {
activateNetwork(injected)
}
})
.catch(() => {
setLoaded(true)
})
}, [activateNetwork, networkActive, networkError])
if (loaded) {
return children
}
return <>Loading</>
}
export default MetamaskProvider
并将MetamaskProvider包裹在您希望钱包在刷新时激活的组件上:
return (
<ThemeProvider theme={darkMode ? darkTheme : lightTheme}>
<StylesProvider injectFirst>
<Paper>
<Router>
<Web3ReactProvider getLibrary={getLibrary}>
<MetamaskProvider>
{...children components}
</MetamaskProvider>
</Web3ReactProvider>
</Router>
</Paper>
</StylesProvider>
</ThemeProvider>
);
它实际上非常简单。您只需将连接地址存储在本地存储中,当用户单击断开连接按钮时,即可从本地存储中删除该地址。基本上,我们使用的条件是,如果本地存储中有acccount,那么我们在加载时连接,如果没有,那么我们必须手动单击连接按钮。请考虑下面的代码。请注意,理想情况下,您应该将逻辑编写为钩子,并在主应用程序中使用钩子,然后在道具中传递"钩子";活动的";从useWeb3React((返回的状态。但为了这个例子的目的,我只是将连接逻辑保存在一个文件中,使其更容易读取
import React, { useState, useEffect } from 'react';
import Web3 from 'web3';
import detectEthereumProvider from '@metamask/detect-provider';
import { useWeb3React } from "@web3-react/core"
import { InjectedConnector } from '@web3-react/injected-connector'
//declare supportated chains
export const injected = new InjectedConnector({
supportedChainIds: [1, 3, 4, 5, 42, 1337, 43114],
})
export default function connButton() {
var web3;
var accounts;
var connected
const [loading, setLoading] = useState(false)
//here we can destructure out various things from web3React such as
//active (which is true if the user is connected and false otherwise)
//activate and deactiveate which we use to instansiate and break the users
//connection
const { active, account, library, connector, activate, deactivate } = useWeb3React()
//set up an elemnt in local storage that we use to hold the connected account
var acc = localStorage.getItem("account")
//function that initialises web3.js
const connectWalletHandler = () => {
if (window.ethereum && window.ethereum.isMetaMask) {
console.log('MetaMask Here!');
web3 = new Web3(window.ethereum);
window.ethereum.request({ method: 'eth_requestAccounts'})
} else {
console.log('Need to install MetaMask');
// setErrorMessage('Please install MetaMask browser extension to interact');
}
console.log(web3.eth.currentProvider)
}
//function that is called on page load if and only if their exists and
//item for the user accoun tin local storage
async function connectOnLoad() {
try {
//here we use activate to create the connection
await activate(injected)
connected = true
} catch (ex) {
console.log(ex)
}
//we use web3.eth to get the accounts to store it in local storage
var accounts1 = await web3.eth.getAccounts();
acc = localStorage.setItem("account", accounts1);
}
//here we use a useEffect so that on page load we can check if there is
//an account in local storage. if there is we call the connect onLoad func
//above which allows us to presist the connection and i also call connectWalletHandler
which sets up web3.js so we can call web3.eth.getAccounts()
useEffect(() => {
if (acc != null) {
connectOnLoad()
}
connectWalletHandler()
}, [])
//however in the case where there is no item in local storage we use this
//function to connect which is called when we click the connect button. its
//essentially the same but we check if local storage is null if it is we activate
//if its not then we disconnect. And when we disconnect we remove the acccount from local storage
async function connectOnClick() {
if (localStorage.getItem("account") == null) {
setLoading(true);
try {
await activate(injected)
connected = true
} catch (ex) {
console.log(ex)
}
// window.location.reload();
var accounts1 = await web3.eth.getAccounts();
console.log(accounts1)
acc = localStorage.setItem("account", accounts1);
console.log(acc)
setTimeout(function(){
setLoading(false)
}, 1600);//wait 2 seconds
} else {
disconnect();
connected = false
}
}
async function disconnect() {
try {
deactivate()
localStorage.removeItem("account");
} catch (ex) {
console.log(ex)
}
}
return (
//remember the active boolean from useReactWeb3() stores a bool
//depending on if the user is or is not connected there for we can
//use this as a conditon to render the button saying "Connect Wallet"
or displaying their address as the text.
<div>
{active ? <button onClick={connectOnClick}>{account.substring(0, 6)}...{account.substring(account.length - 4)}</button> : <button onClick={connectOnClick}>Connect Wallet</button>}
</div>
);
}
然后在你的应用程序.js中,记得把你的整个应用程序包装在标签中。记住,这意味着你需要将web3React导入到你的app.js中,也需要导入
Web3ReactProvider
需要在useWeb3React()
挂钩之前初始化。因此,
将根组件封装在另一个组件中,该组件包含在我的案例中修复的元任务连接的逻辑。
const ConnectionWrapper = ()=> {
// your code to connect metamask
return ( <div>{children}</div>)
}
export default function App({ Component, pageProps }) {
return(
<Web3ReactProvider getLibrary={getLibrary}>
<ConnectionWrapper>
<Component {...pageProps} />
</ConnectionWrapper>
)}