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

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

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

ganache -d

WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第1张图片
打开项目 终端输入

truffle migrate --reset

在区块链上发布一下智能合约
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第2张图片

然后 我们在 src下的 components 目录下创建两个组件
分别是 余额组件 balance.jsx 订单组件 Order.jsx
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第3张图片
然后 在我们 src下的view下的index.jsx组件中引入他们

我们这里 直接导入 然后使用他们
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第4张图片
那么 我们余额的管理 显然是不能用组件传值的 因为他要动态的去变动
redux就是一个非常不错的选择

那么 我们终端执行

npm i --save redux react-redux

引入一下依赖
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第5张图片
然后 我们在src目录下创建文件夹 redux 下面创建一个 store.js
然后 我们还需要一个依赖
终端输入

npm i --save @reduxjs/toolkit

WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第6张图片
然后 我们在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
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第7张图片
然后我们点击修改一下的按钮 可以看到 setTokenWallet 已经成功修改了TokenWallet的值
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第8张图片
好啦 那么 既然已经试过是可以用的了
我们 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文件
在这里多引入一个依赖
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第9张图片
@reduxjs/toolkit 下的 createAsyncThunk
用它来编写异步函数
然后 我们在最下面 这样写

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

然后 balance/fetchBalanceData是这个函数会生成的一个名字 一定要规范一点
然后 我们函数接受两个参数 第一个 是一个data数据对象 然后第二个 我们接受一个对象 里面必须有一个叫dispatch的字段 他是一个回调函数
简单说 这边异步的逻辑完成了 通过 dispatch 回调回去

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

WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第10张图片
逻辑的话 我们先写的比较简单 就把data打印出来看了一下

然后问题来了 我们要在哪里调用呢?
没错 src下的 view下的 index组件
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第11张图片
我们就要在他刚拿完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 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第12张图片
运行代码 查看控制台 也看得到 他是成功将我们的这个web3对象成功的输出了出来
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第13张图片
具体 要怎么获取到我们当前用户的grtoken 我们还是要看看 之前自己写的合约

打开 grtoken的合约 我们会发现 当年我们写了个对象 balanceOf
只需要提供当前账号的地址 就会返回对应的toekn
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第14张图片
我们直接将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 告诉他们操作不上链 不消耗燃料啊 这个很关键
然后我们拿到 控制台输出一下

我们运行代码
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第15张图片
可以看到 我们用户的token 信息 就这样获取出来了 但是这个单位明显是有的问题的 我们要转换一下
但保持最小状态 是利于全局管理的 所以 我们是要转换 但绝对不是在这里转换 这里要存储数据 我们在redux中自然是要保持最小单位的数据管理

最后 等他获取成功了 我们调用 setTokenWallet让他把数据 赋值给我们全局的TokenWallet做管理
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第16张图片
然后是交易所中的 grtoken
这里 我们还是要去看自己之前交易所合约
这里 我们也写了个 balanceof 需要传入当前要查的是哪一种token的地址 和 当前用户的地址
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第17张图片
但是这个要注意下 o的大小写 这个也是我之前留的坑了
我们这里这样写

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

通过Exchange交易所 合约 调用他的balanceof函数 这里 我们通过grToken合约对象 拿到他的地址 然后传入当前账号的地址
最后得到token信息
然后在控制台输出
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第18张图片
运行结果如下
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第19张图片
啊 0 没毛病啊
我们并没有往交易所中存储grtoken 所以是没什么问题的

好 那 这里 我们获取到了 就赋值回调一下
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第20张图片
然后 获取用户当前的ETH 这个就比较简单了 我们很早就演示过
直接编写代码如下

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

直接用web3 对象的getBalance 然后传入当前账号就可以了
运行代码 查看看着他打印
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第21张图片
没有任何问题 还是一个最小单位 没有转换过的
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第22张图片
然后 获取到之后 我们还是一样做个数据的写入
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第23张图片
最后一个 获取在交易所中的 ETH

ETH的地址 我们之前写脚本的时候用过
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第24张图片

const ETHER_ADDRESS = '0x0000000000000000000000000000000000000000';

我们直接将这个拿过来
写到我们 src下的 redux下的balanceSlice下的 index中
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第25张图片
然后 我们最下面直接这样写

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

还是用我们之前交易所写的balanceof 方法 这次 我们的token地址换成了 ETH 账号还是当前账号
一运行 也是零 没毛病啊 毕竟没有存过
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第26张图片
最后 我们还是这样写入一下就好了
WEB3 在 React搭建的Dapp中通过redux全局获取并存储用户ETH与自定义token与交易所存储数量_第27张图片

你可能感兴趣的:(web3,react.js,前端)