WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量

上文 web3 在React dapp中全局管理web3当前登录用户/智能合约等信息中 我们简单操作,将web3的公共信息都存在了window对象上

然后 我们先来启动一下环境

终端输入

javascript 复制代码
ganache -d

打开项目 终端输入

javascript 复制代码
truffle migrate --reset

在区块链上发布一下智能合约

然后 我们在 src下的 components 目录下创建两个组件

分别是 余额组件 balance.jsx 订单组件 Order.jsx

然后 在我们 src下的view下的index.jsx组件中引入他们

我们这里 直接导入 然后使用他们

那么 我们余额的管理 显然是不能用组件传值的 因为他要动态的去变动

redux就是一个非常不错的选择

那么 我们终端执行

javascript 复制代码
npm i --save redux react-redux

引入一下依赖

然后 我们在src目录下创建文件夹 redux 下面创建一个 store.js

然后 我们还需要一个依赖

终端输入

javascript 复制代码
npm i --save @reduxjs/toolkit

然后 我们在src下的redux 目录中创建一个文件夹目录叫 balanceSlice 下面创建一个index.js

参考代码如下

javascript 复制代码
import {createSlice} from "@reduxjs/toolkit";

const balanceSlice = createSlice({
    name:"balance",
    initialState: {
      TokenWallet: "0", //用户自定义token的数量 因为要进行单位转换 所以 用了字符串类型
      TokenExchange: "0", //用户在交易所的token数量  依旧采取字符串类型
      EtherWallet: "0",  //用户的ETH值
      EtherExchange: "0"  //用户在交易所的ETH
    },
    reducers: {
        setTokenWallet(state,action) {
            state.TokenWallet = action.payload
        },
        setTokenExchange(state,action) {
            state.TokenExchange = action.payload
        },
        setEtherWallet(state,action) {
            state.EtherWallet = action.payload
        },
        setEtherExchange(state,action) {
            state.EtherExchange = action.payload
        }
    }
})

export const { setTokenWallet, setTokenExchange, setEtherWallet, setEtherExchange } = balanceSlice.actions;

export default balanceSlice.reducer;

这里 我们存储了当前登录用户的token与ETH 以及 当前用户放在交易所的 token与 ETH

然后 写了更改这些数据的set方法

最后 将我们的数据与几个set函数都导出去

然后 我们src下的 redux 下的 store.js 编写代码如下

javascript 复制代码
import { configureStore } from "@reduxjs/toolkit";
import balanceReducer from "./balanceSlice";

const store = configureStore({
  reducer: {
    balance: balanceReducer
  }
});

export default store;

这里 我们导入 自己刚才写的 balanceSlice下的index 配置store

然后 我们找到 src目录下的 App.js 组件 编写代码如下

javascript 复制代码
import React from 'react';
import Router from "./router/index";
import {Provider} from "react-redux"
import store from "./redux/store";

export default function App() {
  return (
    <Provider store={store}>
      <Router />
    </Provider>
  );
}

其实关键就在于 通过react-redux 导入Provider组件 嵌套我们的路由组件 让所有的路由组件都能享受到共享的数据资源

然后这个数据资源来自 我们配置的redux/store

然后 src目录下的 components目录下 Order.jsx

这里 我们保证这个组件格式不要有问题就好

typescript 复制代码
import React from 'react';

export default function Order() {

  return (
    <div>
      订单组件
    </div>
  );
}

然后 我们在 src下的 components 下的 balance.jsx

编写代码如下

typescript 复制代码
import React from 'react';
import { useSelector, useDispatch } from "react-redux";
import { setTokenWallet } from "../redux/balanceSlice";

export default function Balance() {
  const state = useSelector((state) => state.balance.TokenWallet);
  const dispatch = useDispatch()
  return (
    <div>
      测试组件{state}
      <button onClick={()=>{
        dispatch(setTokenWallet("1000"))
      }}>修改一下</button>
    </div>
  );
}

这里 我们拿取了 TokenWallet 赋值给了state

然后 当按钮点击 我们调用 setTokenWallet修改TokenWallet值的函数

然后 我们启动项目

这里 我们项目运行起来 会看到 TokenWallet 的展示是完全OK的 一个0

然后我们点击修改一下的按钮 可以看到 setTokenWallet 已经成功修改了TokenWallet的值

好啦 那么 既然已经试过是可以用的了

我们 src下 components 下的 balance.jsx 余额组件 先改回一个正常的格式

typescript 复制代码
import React from 'react';
//import { useSelector, useDispatch } from "react-redux";

export default function Balance() {
  //const state = useSelector((state) => state.balance.TokenWallet);
  return (
    <div>
      余额组件
    </div>
  );
}

然后 我们要做的是 在项目初始化时 就拿到用户的这些信息

那么 在哪里拿?

我们打开 src下的 redux下面的 balanceSlice 下的 index.js文件

在这里多引入一个依赖

@reduxjs/toolkit 下的 createAsyncThunk

用它来编写异步函数

然后 我们在最下面 这样写

这里 我们导出了一个异步函数 叫 loadBalanceData

然后 balance/fetchBalanceData是这个函数会生成的一个名字 一定要规范一点

然后 我们函数接受两个参数 第一个 是一个data数据对象 然后第二个 我们接受一个对象 里面必须有一个叫dispatch的字段 他是一个回调函数

简单说 这边异步的逻辑完成了 通过 dispatch 回调回去

typescript 复制代码
export const loadBalanceData = createAsyncThunk(
    "balance/fetchBalanceData",
    async (data, {dispatch}) => {
        console.log(data)
    }
)

逻辑的话 我们先写的比较简单 就把data打印出来看了一下

然后问题来了 我们要在哪里调用呢?

没错 src下的 view下的 index组件

我们就要在他刚拿完WEB3信息的这个地方去调用 然后 data数据 就是要传这个web3 信息进去

我们直接改写代码如下

typescript 复制代码
import { useEffect } from 'react';
import Web3 from "web3";
import grToken from "../build/grToken.json";
import Exchange from "../build/Exchange.json";
import Balance from "../components/balance";
import Orber from "../components/Order";
import { useDispatch } from "react-redux";
import { loadBalanceData } from "../redux/balanceSlice";
export default function PageIndex() {
  const dispatch = useDispatch()
  useEffect(() =>{
      async function start(){
          const WebData = await initialization()
          window.WebData = WebData;
          dispatch(loadBalanceData(WebData))
      }
      start();
  },[dispatch])

  // 获取web 信息
  async function initialization() {
      var web3 = new Web3(Web3.givenProvider || "http://localhost:8545");
      let account = await web3.eth.requestAccounts();
      let networkId = await web3.eth.net.getId();
      const token = await new web3.eth.Contract(grToken.abi,grToken.networks[networkId].address);
      const etoken = await new web3.eth.Contract(Exchange.abi,Exchange.networks[networkId].address);
      return {
        web3,
        account: account[0],
        grToken: token,
        Exchange: etoken
      }
  }
  return (
    <div>
      <Balance></Balance>
      <Orber></Orber>
      欢迎来到 Web3 练习的世界
    </div>
  );
}

做了部分语法改动 但其实说到底 唯一的改变就是 在initialization返回web3 信息成功后

我们调用了loadBalanceData 并传入了 我们刚获取到的web3 信息

然后 我们loadBalanceData其实也就输出了一下这个传入的data数据

运行代码 查看控制台 也看得到 他是成功将我们的这个web3对象成功的输出了出来

具体 要怎么获取到我们当前用户的grtoken 我们还是要看看 之前自己写的合约

打开 grtoken的合约 我们会发现 当年我们写了个对象 balanceOf

只需要提供当前账号的地址 就会返回对应的toekn

我们直接将src下redux 下 balanceSlice下的inex 中的 loadBalanceData代码更改如下

typescript 复制代码
export const loadBalanceData = createAsyncThunk(
    "balance/fetchBalanceData",
    async (data, {dispatch}) => {
        //从data中将web3信息都结构出来
        const {
            web3,
            account,
            grToken,
            Exchange
        } = data;
        //用户当前用户token信息
        const TokenWallet = await grToken.methods.balanceOf(account).call()
        console.log(TokenWallet)
       //获取当前用户在交易所的token信息

    }
)

这里 我们通过grToken合约的balanceof函数 传入account当前用户 去获取当前用户的grtoken信息

这里注意要用 call 告诉他们操作不上链 不消耗燃料啊 这个很关键

然后我们拿到 控制台输出一下

我们运行代码

可以看到 我们用户的token 信息 就这样获取出来了 但是这个单位明显是有的问题的 我们要转换一下

但保持最小状态 是利于全局管理的 所以 我们是要转换 但绝对不是在这里转换 这里要存储数据 我们在redux中自然是要保持最小单位的数据管理

最后 等他获取成功了 我们调用 setTokenWallet让他把数据 赋值给我们全局的TokenWallet做管理

然后是交易所中的 grtoken

这里 我们还是要去看自己之前交易所合约

这里 我们也写了个 balanceof 需要传入当前要查的是哪一种token的地址 和 当前用户的地址

但是这个要注意下 o的大小写 这个也是我之前留的坑了

我们这里这样写

typescript 复制代码
const TokenExchange = await Exchange.methods.balanceof(grToken.options.address,account).call()
console.log(TokenExchange)

通过Exchange交易所 合约 调用他的balanceof函数 这里 我们通过grToken合约对象 拿到他的地址 然后传入当前账号的地址

最后得到token信息

然后在控制台输出

运行结果如下

啊 0 没毛病啊

我们并没有往交易所中存储grtoken 所以是没什么问题的

好 那 这里 我们获取到了 就赋值回调一下

然后 获取用户当前的ETH 这个就比较简单了 我们很早就演示过

直接编写代码如下

typescript 复制代码
const EtherWallet = await web3.eth.getBalance(account)
console.log(EtherWallet)

直接用web3 对象的getBalance 然后传入当前账号就可以了

运行代码 查看看着他打印

没有任何问题 还是一个最小单位 没有转换过的

然后 获取到之后 我们还是一样做个数据的写入

最后一个 获取在交易所中的 ETH

ETH的地址 我们之前写脚本的时候用过

typescript 复制代码
const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';

我们直接将这个拿过来

写到我们 src下的 redux下的balanceSlice下的 index中

然后 我们最下面直接这样写

typescript 复制代码
//获取当前用户交易所下的ETH
const EtherExchange = await Exchange.methods.balanceof(ETHER_ADDRESS,account).call()
console.log(EtherExchange)

还是用我们之前交易所写的balanceof 方法 这次 我们的token地址换成了 ETH 账号还是当前账号

一运行 也是零 没毛病啊 毕竟没有存过

最后 我们还是这样写入一下就好了

相关推荐
安冬的码畜日常41 分钟前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js
小白学习日记1 小时前
【复习】HTML常用标签<table>
前端·html
丁总学Java2 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
yanlele2 小时前
前瞻 - 盘点 ES2025 已经定稿的语法规范
前端·javascript·代码规范
懒羊羊大王呀2 小时前
CSS——属性值计算
前端·css
DOKE3 小时前
VSCode终端:提升命令行使用体验
前端
xgq3 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
用户3157476081353 小时前
前端之路-了解原型和原型链
前端
永远不打烊3 小时前
librtmp 原生API做直播推流
前端