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

news/2024/7/15 17:12:46 标签: web3, react.js, 前端

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

然后 我们先来启动一下环境
终端输入

ganache -d

在这里插入图片描述
打开项目 终端输入

truffle migrate --reset

在区块链上发布一下智能合约
在这里插入图片描述

然后 我们在 src下的 components 目录下创建两个组件
分别是 余额组件 balance.jsx 订单组件 Order.jsx
在这里插入图片描述
然后 在我们 src下的view下的index.jsx组件中引入他们

我们这里 直接导入 然后使用他们
在这里插入图片描述
那么 我们余额的管理 显然是不能用组件传值的 因为他要动态的去变动
redux就是一个非常不错的选择

那么 我们终端执行

npm i --save redux react-redux

引入一下依赖
在这里插入图片描述
然后 我们在src目录下创建文件夹 redux 下面创建一个 store.js
然后 我们还需要一个依赖
终端输入

npm i --save @reduxjs/toolkit

在这里插入图片描述
然后 我们在src下的redux 目录中创建一个文件夹目录叫 balanceSlice 下面创建一个index.js

参考代码如下

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 编写代码如下

import { configureStore } from "@reduxjs/toolkit";
import balanceReducer from "./balanceSlice";

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

export default store;

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

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

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
这里 我们保证这个组件格式不要有问题就好

import React from 'react';

export default function Order() {

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

然后 我们在 src下的 components 下的 balance.jsx
编写代码如下

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 余额组件 先改回一个正常的格式

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 回调回去

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

在这里插入图片描述
逻辑的话 我们先写的比较简单 就把data打印出来看了一下

然后问题来了 我们要在哪里调用呢?
没错 src下的 view下的 index组件
在这里插入图片描述
我们就要在他刚拿完WEB3信息的这个地方去调用 然后 data数据 就是要传这个web3 信息进去

我们直接改写代码如下

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代码更改如下

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的大小写 这个也是我之前留的坑了
我们这里这样写

const TokenExchange = await Exchange.methods.balanceof(grToken.options.address,account).call()
console.log(TokenExchange)

通过Exchange交易所 合约 调用他的balanceof函数 这里 我们通过grToken合约对象 拿到他的地址 然后传入当前账号的地址
最后得到token信息
然后在控制台输出
在这里插入图片描述
运行结果如下
在这里插入图片描述
啊 0 没毛病啊
我们并没有往交易所中存储grtoken 所以是没什么问题的

好 那 这里 我们获取到了 就赋值回调一下
在这里插入图片描述
然后 获取用户当前的ETH 这个就比较简单了 我们很早就演示过
直接编写代码如下

const EtherWallet = await web3.eth.getBalance(account)
console.log(EtherWallet)

直接用web3 对象的getBalance 然后传入当前账号就可以了
运行代码 查看看着他打印
在这里插入图片描述
没有任何问题 还是一个最小单位 没有转换过的
在这里插入图片描述
然后 获取到之后 我们还是一样做个数据的写入
在这里插入图片描述
最后一个 获取在交易所中的 ETH

ETH的地址 我们之前写脚本的时候用过
在这里插入图片描述

const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';

我们直接将这个拿过来
写到我们 src下的 redux下的balanceSlice下的 index中
在这里插入图片描述
然后 我们最下面直接这样写

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

还是用我们之前交易所写的balanceof 方法 这次 我们的token地址换成了 ETH 账号还是当前账号
一运行 也是零 没毛病啊 毕竟没有存过
在这里插入图片描述
最后 我们还是这样写入一下就好了
在这里插入图片描述


http://www.niftyadmin.cn/n/5148212.html

相关文章

亚马逊、美客多卖家测评:如何建立养号团队实现运营化式测评?

大家好&#xff0c;我是跨境电商测评养号7年从事经验的珑哥。养号环境软件开发&#xff0c;深度解决各跨境平台矩阵养号防关联、砍单、F号问题。关注珑哥解决更多跨境养号测评问题。 测评&#xff0c;相信这个词对于大部分跨境卖家来说&#xff0c;想必都不陌生&#xff0c;因…

linux环境下编译,安卓平台使用的luajit库

一、下载luajit源码 1、linux下直接下载&#xff1a; a、使用curl下载&#xff1a;https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz b、git下载地址&#xff1b;https://github.com/LuaJIT/LuaJIT.git 2、Windows下载好zip文件&#xff0c;下载地址&#xff1a;https…

【后端开发】手写一个简单的线程池

半同步半异步线程池 半同步半异步线程池分为三层&#xff1a; 同步服务层 —— 处理来自上层的任务请求&#xff0c;将它们加入到排队层中等待处理。 同步排队层 —— 实际上是一个“同步队列”&#xff0c;允许多线程添加/取出任务&#xff0c;并保证线程安全。 异步服务层…

Docker Compose部署Spug:实现内网穿透

文章目录 前言1. Docker安装Spug2 . 本地访问测试3. Linux 安装cpolar4. 配置Spug公网访问地址5. 公网远程访问Spug管理界面6. 固定Spug公网地址 前言 Spug 面向中小型企业设计的轻量级无 Agent 的自动化运维平台&#xff0c;整合了主机管理、主机批量执行、主机在线终端、文件…

python的文件读写

读写文件是最常见的IO操作。 在磁盘上读写文件的功能都是由操作系统提供的&#xff0c;而现代操作系统不允许普通的程序直接操作磁盘。所以&#xff0c;读写文件就是请求操作系统打开一个文件对象&#xff08;通常称为文件描述符&#xff09;&#xff0c;然后&#xff0c;通过…

测试用例设计方法:正交试验法详解!

01、正交试验法介绍 正交试验法是研究多因素、多水平的一种试验法&#xff0c;它是利用正交表来对试验进行设计&#xff0c;通过少数的试验替代全面试验&#xff0c;根据正交表的正交性从全面试验中挑选适量的、有代表性的点进行试验&#xff0c;这些有代表性的点具备了“均匀…

若依分离版——配置多数据源(mysql和oracle),实现一个方法操作多个数据源

目录 一、若依平台配置 二、编写oracle数据库访问的各类文件 三. 一个方法操作多个数据源 一、若依平台配置 1、在ruoyi-admin的pom.xml添加依赖 <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version…

【二、http】go的http基本请求设置(设置查询参数、定制请求头)get和post类似

一、设置url后边的参数&#xff0c;&#xff08;get和post请求为例子&#xff09; func requstByParamsGet(){requst, err : http.NewRequest(http.MethodGet, "http://httpbin.org/get", nil)if err ! nil {fmt.Println("ss")}params : make(url.Values)p…