The web3 React dapp project gets canceled and completed and all order data from the blockchain through events and stores them in redux.

Okay, above, web3 uses antd to build the basic structure of the order component in the React dapp. We have demonstrated a basic order component.

Then let’s continue and start with the environment.
ganache terminal run

ganache -d

MetaMask Log in

Then open the project and publish the contract

truffle migrate --reset


Then run the test script to transfer ETH and grToken to the exchange and create two orders.

truffle exec .\scripts\test.js


Then run the dapp project

Okay, then let’s get started

We still need to use redux to manage global order data
In this way, we don’t need to consider the issue of interface updates. Redux will handle it for us.

Here we first find the balanceSlice directory under redux under src in the root directory
Create an orderSlice.js below
The reference code is as follows

import {<!-- --> createSlice, createAsyncThunk } from "@reduxjs/toolkit";;

const orderSlice = createSlice({<!-- -->
    name:"order",
    initialState: {<!-- -->
        Cancelorders: [], //Cancelled orders
        Fillorders: [], //Completed orders
        Allorders: [] //All orders
    },
    reducers: {<!-- -->
        setCancelorders(state,action) {<!-- -->
            state.Cancelorders = action.payload
        },
        setFillorders(state,action) {<!-- -->
            state.Fillorders = action.payload
        },
        setAllorders(state,action) {<!-- -->
            state.Allorders = action.payload
        }
    }
})

export const {<!-- --> setCancelorders, setFillorders, setAllorders } = orderSlice.actions;

export default orderSlice.reducer;

export const loadCancelorderData = createAsyncThunk(
    "order/fetchCancelorderData",
    async (data, {<!-- -->dispatch}) => {<!-- -->
        
    }
)

Here we simply wrote a redux data structure. The data is divided into three collections: all canceled orders, all completed orders, all orders.
Then write corresponding set functions for three of them respectively.

But our asynchronous function cannot be written as one. Many people may think that we write an asynchronous function to first get Cancelorders, then get Fillorders, and finally get Allorders.
This is fine as the current development perspective, but we need to consider subscription and unsubscription later.
Therefore, the data obtained cannot be put together
Here we first write a test of Cancelorders
Of course, we still need to introduce it first. We find index.js under redux under src in the root directory.
Import the orderSlice you just wrote

Then we use this function in the index.jsx component of the view under src

Here we imported the loadCancelorderData we wrote and called it. Although loadCancelorderData and loadBalanceData are both asynchronous, we do not need to consider the issue of sequential execution because there is no correlation between them. Who executes first and which last has little impact.

Then we come to the loadCancelorderData function. The most important thing here is to get the contract of the exchange.
Because the orders are all on the exchange

Let’s first print it in the console and take a look

You can see that the contracts on this exchange are available.

Then we open the contract on the exchange and see the overall structure of the order. This is how we made a storage before.

But here we use mapping in the form of an object. If we want to get the corresponding data, we need to pass in the id.
Then the most basic solution is to change it to an array structure. But obviously I will not choose to change the contract after writing it halfway.
Well, you should still remember that I said before that the blockchain can store event information and cannot be tampered with.

Remember the incident we wrote about before? When we publish an order, cancel an order, or execute an order, events will be recorded, and we can directly get the records of these events.

Here we directly change the loadCancelorderData event code as follows

export const loadCancelorderData = createAsyncThunk(
    "order/fetchCancelorderData",
    async (data, {<!-- -->dispatch}) => {<!-- -->
        const {<!-- -->
            Exchange
        } = data;

        const result = await Exchange.getPastEvents("Cancel", {<!-- -->
          fromBlock:0,
          toBlock: "latest"
        })
        console.log(result)
    }
)

Here we call an event that comes with the exchange called getPastEvents. This function can get the events recorded on the chain before the contract.
Then the event we need to get is Cancel, which we wrote on the contract before to record the event of canceling the order.
Then the two parameters fromBlock mean that we want the 0th block to simply say the latest and then latest means we want the latest
Then output the print result
After running the code, we look at the console

Obviously we succeeded and got an array. Because we only had a canceled order, there was only one piece of data.

Then, a lot of information outside is block information. In fact, the information we write in the real order itself is in returnValues.

There is a returnValues in each order data. This is the field we wrote ourselves.
We can filter him out

we can write like this

Or organize it into an array, but we only need the returnValues field in it
The running results are as follows

So, now that the data is obtained, we call dispatch and call the specified set function to write it back to the corresponding data.

Then everything is the same. Here we write another event. The reference code is as follows

export const loadAllrderData = createAsyncThunk(
    "order/fetchAlorderData",
    async (data, {<!-- -->dispatch}) => {<!-- -->
        const {<!-- -->
            Exchange
        } = data;

        const result = await Exchange.getPastEvents("Order", {<!-- -->
          fromBlock:0,
          toBlock: "latest"
        })
        const Allorders = result.map(item=>item.returnValues)
        dispatch(setAllorders(Allorders))
    }
)

The format for obtaining canceled order data is basically the same as what we just wrote.
Just here we changed the name and the event called is Order
This is what our previous contract used to record the created order.

Then get the data and do a write-back of the data

Then the query to complete the order is exactly the same.

export const loadFillorderData = createAsyncThunk(
    "order/fetchFillorderData",
    async (data, {<!-- -->dispatch}) => {<!-- -->
        const {<!-- -->
            Exchange
        } = data;

        const result = await Exchange.getPastEvents("Fill", {<!-- -->
          fromBlock:0,
          toBlock: "latest"
        })
        const Fillorders = result.map(item=>item.returnValues)
        dispatch(setFillorders(Fillorders))
    }
)

Here, change the name, and then here we are going to call Fill before our contract definition to record the event of filling the order.

Finally, get the data and write it

After writing, we go to index.jsx in the view directory in the src directory, import the other two events together, and then call them

Then we run the code and the data is obviously entered.

But our console will report a warning

Good guy is still very scary Manshanhong

In fact, this problem is because our order is a non-serialized data, which is a problem that occurs in redux.

Here we can clearly see that the data has entered, and the storage format looks the same as we expected.
Her warning is that this is non-serialized data and does not comply with our specifications. If something goes wrong in the future, don’t blame our framework.

If you don’t want it to come out, you can directly turn off a check on the data in redux.

We find index.js in the redux directory under the src directory and add such a configuration to configureStore.

middleware:getDefaultMiddleware => getDefaultMiddleware({<!-- -->
    serializableCheck:false
})

Turn off his inspection of the data

Then we run it again and the console is clean

Okay, then we have our order data.