安装依赖
在我们开始之前安装必要的包:
$ yarn add @web3-react/core @web3-react/injected-connector
$ yarn add @ethersproject/providers
- @web3-react 为React应用程序提供了非常好的 web3 实用程序,以与 web3 兼容的区块链进行通信。
- @ethersproject/providers 它包含常见的 Provider 类、用于处理提供者的实用函数,并重新导出实现自定义 Provider 所需的许多类和类型。
连接到钱包
第一步是将我们的 React项目 连接到浏览器钱包。首先我们需要创建几个文件。
我们创建了一个 InjectedConnector 并指定了支持的链 id 以包含 Clover 链 id 【1, 3, 4, 5, 42】。
// connector.js
import { InjectedConnector } from '@web3-react/injected-connector'
export const injected = new InjectedConnector({ supportedChainIds: [1, 3, 4, 5, 42] })
hooks.js 提供了几个钩子来帮助连接钱包。
// hooks.js
import { useState, useEffect } from 'react'
import { useWeb3React } from '@web3-react/core'
import { injected } from './connectors'
export function useEagerConnect() {
const { activate, active } = useWeb3React()
const [tried, setTried] = useState(false)
useEffect(() => {
injected.isAuthorized().then((isAuthorized) => {
if (isAuthorized) {
activate(injected, undefined, true).catch(() => {
setTried(true)
})
} else {
setTried(true)
}
})
}, []) // intentionally only running on mount (make sure it's only mounted once :))
// if the connection worked, wait until we get confirmation of that to flip the flag
useEffect(() => {
if (!tried && active) {
setTried(true)
}
}, [tried, active])
return tried
}
export function useInactiveListener(suppress = false) {
const { active, error, activate } = useWeb3React()
useEffect(() => {
const { ethereum } = window
if (ethereum && ethereum.on && !active && !error && !suppress) {
const handleConnect = () => {
console.log("Handling 'connect' event")
activate(injected)
}
const handleChainChanged = (chainId) => {
console.log("Handling 'chainChanged' event with payload", chainId)
activate(injected)
}
const handleAccountsChanged = (accounts) => {
console.log("Handling 'accountsChanged' event with payload", accounts)
if (accounts.length > 0) {
activate(injected)
}
}
const handleNetworkChanged = (networkId) => {
console.log("Handling 'networkChanged' event with payload", networkId)
activate(injected)
}
ethereum.on('connect', handleConnect)
ethereum.on('chainChanged', handleChainChanged)
ethereum.on('accountsChanged', handleAccountsChanged)
ethereum.on('networkChanged', handleNetworkChanged)
return () => {
if (ethereum.removeListener) {
ethereum.removeListener('connect', handleConnect)
ethereum.removeListener('chainChanged', handleChainChanged)
ethereum.removeListener('accountsChanged', handleAccountsChanged)
ethereum.removeListener('networkChanged', handleNetworkChanged)
}
}
}
}, [active, error, suppress, activate])
}
Spinner.js 实现了一个简单的 Spinner 组件,可以用作加载状态。
// Spinner.js
import React from 'react'
export function Spinner(props) {
const { color, ...rest } = props
return (
<svg width="38" height="38" viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" stroke={color} {...rest}>
<g fill="none" fillRule="evenodd">
<g transform="translate(1 1)" strokeWidth="2">
<circle strokeOpacity=".5" cx="18" cy="18" r="18" />
<path d="M36 18c0-9.94-8.06-18-18-18">
<animateTransform
attributeName="transform"
type="rotate"
from="0 18 18"
to="360 18 18"
dur="1s"
repeatCount="indefinite"
/>
</path>
</g>
</g>
</svg>
)
}
更新 App.js 以将其内容设置为:
我们将 Web3ReactProvider 添加到应用程序的根目录,并在 App 组件中包含 useEagerConnect 钩子。我们还包括 ChainId 组件,它将显示连接的链 ID,如果未检测到连接,则显示未连接。
// App.js
import { Web3ReactProvider, useWeb3React, } from '@web3-react/core'
import { Web3Provider } from '@ethersproject/providers'
import { useEagerConnect, useInactiveListener } from './hooks'
import './App.css';
function getLibrary(provider) {
const library = new Web3Provider(provider)
library.pollingInterval = 5000
return library
}
function ChainId() {
const { chainId, library } = useWeb3React()
return (
<div className="ChainIdWrapper">
<span>Chain Id</span>
<span role="img" aria-label="chain">
⛓
</span>
<span className="ChainIdText">{chainId ?? 'Not Connected'}</span>
</div>
)
}
function App() {
const triedEager = useEagerConnect()
return (
<div className="App">
<header className="App-header">
<h1>Counter Example </h1>
<ChainId/>
<p>
Current value: n/a
</p>
<button className="CounterButton">Inc Counter</button>
<button className="CounterButton">Dec Counter</button>
</header>
</div>
);
}
export default function() {
return (
<Web3ReactProvider getLibrary={getLibrary}>
<App />
</Web3ReactProvider>
)
}
启动应用程序你会在ChainId组件中看到not connected。这是 find 因为我们还没有实现连接逻辑。 但是你可以通过从 MetaMask 手动连接到 web 应用程序来测试它,尝试弄清楚如何自己做。
添加连接按钮
现在让我们添加一个按钮来触发钱包连接对话框。
//App.js
import React from 'react'
import { Spinner } from './Spiner'
import { injected } from './connectors'
function ConnectChain(props) {
const context = useWeb3React()
const { connector, library, chainId, account, activate, deactivate, active, error } = context
const [activatingConnector, setActivatingConnector] = React.useState()
React.useEffect(() => {
if (activatingConnector && activatingConnector === connector) {
setActivatingConnector(undefined)
}
}, [activatingConnector, connector])
const activating = injected === activatingConnector
const connected = injected === connector
const disabled = !props.triedEager || !!activatingConnector || !!error
useInactiveListener(!props.triedEager || !!activatingConnector)
let isDisconnect = !error && chainId
const buttonText = isDisconnect ? 'Disconnect' : (activating ? 'Connectting' : 'Connect' )
return (
<button
style={{
borderColor: activating ? 'orange' : connected ? 'green' : 'unset',
cursor: disabled ? 'unset' : 'pointer',
position: 'relative',
}}
className="ConnectButton"
disabled={disabled}
onClick={() => {
if (!isDisconnect) {
setActivatingConnector(injected)
activate(injected)
} else {
deactivate()
}
}}
>
<div
style={{
position: 'absolute',
top: '0',
left: '0',
height: '100%',
display: 'flex',
alignItems: 'center',
color: 'black',
margin: '0 0 0 1rem'
}}
>
{activating && <Spinner color={'red'} style={{ height: '50%', marginLeft: '-1rem' }} />}
</div>
{ buttonText }
</button>
)
}
然后添加按钮的 css 类文件
.ConnectButton {
background-color: #4CAF50;
border: none;
color: white;
margin-top: 15px;
margin-bottom: 15px;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
width: 200px;
}
.ConnectButton:disabled {
background-color: grey;
color: black;
}
ConnectChain 组件简单地呈现一个按钮,如果它没有连接,点击它会触发 web3 连接对话框。
<ConnectChain triedEager={triedEager} />
重新加载页面,连接按钮将出现,您可以单击它打开连接对话框。 连接到钱包后,单击按钮将断开它。