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
点个关注么么哒