web3.js+react-hooks+antd

651 阅读4分钟

1.创建react项目

yarn create react-app my-app --template typescript

2.引入包

在删除无关文件后,引入所需的包

#引入路由
yarn add react-router-dom @types/react-router-dom 
yarn add antd axios less 
# 修改react的配置-这一步主要是为了修改打包的配置
yarn add -D customize-cra react-app-rewired 
# 使用less-因为用了antd
yarn add -D less-loader@6.0.0

#该步骤完成后

3.路由配置

 // 使用的是BrowserRouter 个人不喜欢HashRouter后边的#号 
// ps:  <Route exact path="/" component={Index} /> 这里的exact一定要加上,不然跳转不了路由,究其原因:
1.精准匹配
    如果不写的话
    <Switch>
       <Route path='/' component={InitHome}/>
       <Route path='/about' component={About}/>
       <Route path='/home'component={Home}/>
     </Switch>

    那么path='/'也会匹配'/about''/home'导致的结果就是下面两个路由就没用了

    path='/'

    转载:https://blog.csdn.net/qq_42339350/article/details/111691851
## 第二个需要注意的是嵌套路由的父router不能添加上exact 原因为:    
    使用嵌套路由在父级不能用exact, 因为当你匹配路由时路径加了子路由,导致父级路由路径不匹配从而父子组件都显示
    不了。例如你这个/user/details 使用了exact,当路径变为/user/details/msg是匹配不到/user/details的,这样的
    话就无法渲染Details而msg又是在Detail里面所以也不会渲染
    

import React, { lazy, Suspense} from 'react'
import { BrowserRouter,HashRouter, Switch, Route } from 'react-router-dom'

import BaseLayout  from '../layout/BaseLayout'

// login
import Login from '../pages/Login'
// Home Page
const Index = lazy(() => import(/* webpackChunkName: 'Index'*/ '../pages/Home'))
// Games Page
const Games = lazy(() => import(/* webpackChunkName: 'Index'*/ '../pages/Game'))
// NFC page
const Nft = lazy(() => import(/* webpackChunkName: 'Index'*/ '../pages/Nft'))


const RouterContainer: React.FC = (props: any) => {

  return (
    <>
      <BrowserRouter>
        <Switch>
          <Route
            path="/"
            render={() =>
                <BaseLayout>
                  <Suspense fallback={<div>Loading...</div>}>
                    <Switch>
                      <Route exact path="/" component={Index} />
                      <Route path="/Index" component={Index} />
                      <Route path="/Game" component={Games} />
                      <Route path="/Nft" component={Nft} />
                    </Switch>
                  </Suspense>
                </BaseLayout> 
            }
          />
        </Switch>
      </BrowserRouter>
    </>
  )
}




export default RouterContainer

4.按需加载和config-overrides.js配置

首页引包 yarn add -D react-app-rewired customize-cra
// package.json 修改,
//如果想配置多环境可参考 https://zhuanlan.zhihu.com/p/95855648 
...
"scripts": { 
    "start": "react-app-rewired start", 
    "build": "react-app-rewired build", 
    "test": "react-app-rewired test" 
},
// config-overrides.js 
const path = require('path')
const {
  override,
  addLessLoader,
  addWebpackAlias,
  overrideDevServer,
  fixBabelImports
} = require('customize-cra')
const { getThemeVariables } = require('antd/dist/theme');
// 配置代理
const proxy = {
  '/api': {
    target: 'http://xxx:3000',
    changeOrigin: true
  }
}
const devServerConfig = () => config => {
  return {
    ...config,
    proxy
  }
}

// 修改端口号
process.env.PORT = 3030

module.exports = {
  webpack: override(
    addWebpackAlias({
      // 路径别名,还需要配置tsconfig.json、tsconfig-base.json,在后面,可配置多个路径别名
        '@': path.resolve(__dirname, 'src/')
    }),
    // antd按需加载
    fixBabelImports('import', { 
      libraryName: 'antd',
      libraryDirectory: 'es',
      style: true // 支持less
    }),
    // 配置less
    addLessLoader({
      lessOptions: {
        javascriptEnabled: true, // 启用支持内联javascript
        // modifyVars: { 
        //   // @primary-color: #1890ff; // 全局主色
        //   // @link-color: #1890ff; // 链接色
        //   // @success-color: #52c41a; // 成功色
        //   // @warning-color: #faad14; // 警告色
        //   // @error-color: #f5222d; // 错误色
        //   // @font-size-base: 14px; // 主字号
        //   // @heading-color: rgba(0, 0, 0, 0.85); // 标题色
        //   // @text-color: rgba(0, 0, 0, 0.65); // 主文本色
        //   // @text-color-secondary: rgba(0, 0, 0, 0.45); // 次文本色
        //   // @disabled-color: rgba(0, 0, 0, 0.25); // 失效色
        //   // @border-radius-base: 2px; // 组件/浮层圆角
        //   // @border-color-base: #d9d9d9; // 边框色
        //   // @box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08),
        //   //   0 9px 28px 8px rgba(0, 0, 0, 0.05); // 浮层阴影
        // },
        //  localIdentName: '[local]--[hash:base64:5]'、
        //  开启暗黑模式的情况下使用自定义主题
        modifyVars:{
          ...getThemeVariables({
            dark: true, // 开启暗黑模式
            compact: false, // 开启紧凑模式
          }),
          '@primary-color': '#3c8618',
        }
      }
    })
  ),
  devServer: overrideDevServer(devServerConfig()) 
}
# 新增tsconfig-base.json
    
    {
        "compilerOptions": {
          "baseUrl": ".",
          "paths": {
            "@/*": ["src/*"]
          }
        }
   }
# 在tsconfig.ts中
{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  // 该步骤引入额外的包
  "extends": "./tsconfig-base.json",
  "include": [
    "src"
  ]
}

  ** 以上步骤为react在不eject的情况下的使用,如果需要额外自己配置webpack.config.ts,eject之后配置主题的步骤我失败了,如果有了解的同学请联系我**

5.引入web3.js

yarn add web3.js
// web3.js目前对本人来说,主要是为了开发dapp,涉及的步骤主要有连接钱包,登录成功后的交易,链上数据的存储步骤(登录成功后的交易,链上数据的存储步骤,我会写在后边。ps:其实还没看)
// 首先链接钱包
// Login.tsx
import { Button } from "antd";
import { useState } from "react";

const Login = (props:any) => {
  const [isConnecting, setIsConnecting] = useState(false);
    console.log(props);

  const detectProvider = () => {
    let provider;
    if (window.ethereum) {
      provider = window.ethereum;
    } else if (window.web3) {
      provider = window.web3.currentProvider;
    } else {
      window.alert("No Ethereum browser detected! Check out MetaMask");
    }
    return provider;
  };

  const onLoginHandler = async () => {
    const provider = detectProvider();
    if (provider) {
      if (provider !== window.ethereum) {
        console.error(
          "Not window.ethereum provider. Do you have multiple wallet installed ?"
        );
      }
      setIsConnecting(true);
      await provider.request({
        method: "eth_requestAccounts",
      });
      setIsConnecting(false);
    }
    props.onLogin(provider);
  };

  return (
      <div>
        <Button onClick={onLoginHandler} style={{cursor:'pointer'}}>Connect</Button> 
      </div>

  );
};

export default Login;
Home.tsx或者Index.tsx import {Login} from 'xxx'
    
   <div >
      {!isConnected?(<Login onLogin={onLogin}></Login>):(<b style={{textAlign:'center',color:'#3c8618',fontSize:'1rem'}}>link success</b>)}
   </div>
  #此时如果电脑上如果有MetaMask,已经可以链接了,当然有的公司会让你点击链接弹出多个钱包选项,可以使用antd的moddal组件自行添加,也可使用web3-modalui组件,这里我使用的是web3-modal
  ps: 因为还没去看其他钱包怎么连接,应该都差不多,弹出来之后点击钱包,链接
      
      yarn add we3-modal 
      import { Button } from "antd";
        import React,{useState,useEffect} from "react";
        import styles from './Home.module.less'

        import Web3Modal from "web3modal"
        import WalletConnectProvider from '@walletconnect/web3-provider'
        // import WalletLink from 'walletlink'
        const INFURA_ID = '460f40a212360564ac4a4f4b3fffb032dad'
        const providerOptions = {
          walletconnect: {
            package: WalletConnectProvider, // required
            options: {
              infuraId: INFURA_ID, // required
            },
          },
          //配置多个钱包的地方
          // 'custom-walletlink': {
          //   display: {
          //     logo: 'https://play-lh.googleusercontent.com/PjoJoG27miSglVBXoXrxBSLveV6e3EeBPpNY55aiUUBM9Q1RCETKCOqdOkX2ZydqVf0',
          //     name: 'Coinbase',
          //     description: 'Connect to Coinbase Wallet (not Coinbase App)',
          //   },
          //   options: {
          //     appName: 'Coinbase', // Your app name
          //     networkUrl: `https://mainnet.infura.io/v3/${INFURA_ID}`,
          //     chainId: 1,
          //   },
          //   package: WalletLink,
          //   connector: async (_:any, options:any) => {
          //     const { appName, networkUrl, chainId } = options
          //     const walletLink = new WalletLink({
          //       appName,
          //     })
          //     const provider = walletLink.makeWeb3Provider(networkUrl, chainId)
          //     await provider.enable()
          //     return provider
          //   },
          // },
        }

        const  web3Modals  =  new  Web3Modal ( { 
          network : "mainnet" ,  // optional 
          cacheProvider : false ,  // optional 
          providerOptions:providerOptions
        })

        function Home(props:any){
          console.log(props);
            return (
              <div>
               <Button onClick={async (e) => {
                 const  provider  =  await web3Modals.connect()
                 console.log(provider);

               }}>链接</Button>
              </div>
            );
        }

        export default Home
       

转载及参考

    https://juejin.cn/post/7027019191282565128
    https://zhuanlan.zhihu.com/p/95855648
    https://blog.csdn.net/qq_42339350/article/details/111691851

点个关注么么哒