Build a decentralized CRUD application using Typescript, React, and DB3.js
xutweety
Posted on March 3, 2023
Introduction
DB3.js is a JavaScript API development toolkit that complements Web3.js in dApp development. With it, you can write data into the DB3 Network (a decentralized database), query data, and more.
To help more front-end developers seamlessly switch from the web2 world to the web3 era and quickly build decentralized applications, DB3.js adopt the philosophy of the Firebase SDK in mind because DB3 Network aims to become a decentralized alternative to Firebase Firestore.
Firebase is one of the most popular backend-as-a-service options in modern technology stacks, suitable for multiple platforms, including mobile, Unity, Java, C++, and web. The drawback of the past SDK V8 version was its large size, which caused slow network connections. V9 version made improvements such as functional programming style, no-side-effect imports, etc. These more advanced design concepts reduced the size of the V9 version by 80%. How to design DB3.js to be more lightweight and help decentralized applications improve their user experience on mobile devices, etc., is also one of the directions in which DB3.js needs to learn from Firebase.
Using DB3.js to Show the CRUD Process of Decentralized Applications
This article will transform a classic demo example of TodoMVC into a decentralized TodoMVC using DB3.js. We will show how to use DB3.js to perform CRUD operations and demonstrate the process of writing, reading, modifying, and deleting data in decentralized applications. We will complete a to-do list application as shown below. You can click here to view the demo code.
During the process, we will display the following CRUD operations:
Create: Enter a new to-do item, add the to-do item to the list, and complete the addition process by pressing Enter.
Read: Listen to the document in the collection and display the list, including all to-dos, active to-dos, and completed to-dos.
Update: Modify the content of the to-do item; when it is done, click it to mark it as completed.
Delete: Delete the to-do items.
(Please note that there may be some instability as we connect to a test node in our network. If you encounter any problems, you can try again later or submit a bug on GitHub)
Running the Demo Directly
Step 1: Start DB3 Network
git clone https://github.com/dbpunk-labs/db3.git
cd db3 && bash install_env.sh && cargo build
# start localnet
cd tools && sh start_localnet.sh
After starting, you can see network activity similar to the following:
Step 2: Start DB3 CLI, Create Database, and Collection
The database address 0x7720f39c6bf077582ab89797c90ca7701ea82ea9
in the codeblock below is the database address for the todo application to be created next. Then, we create new collection under its database address, named. todos
.
(base) ✘ xuman@192 ~/Documents/GitHub/dbpunkslabs/db3 main ./target/debug/db3 console
██████╗ ██████╗ ██████╗
██╔══██╗██╔══██╗╚════██╗
██║ ██║██████╔╝ █████╔╝
██║ ██║██╔══██╗ ╚═══██╗
██████╔╝██████╔╝██████╔╝
╚═════╝ ╚═════╝ ╚═════╝
@db3.network🚀🚀🚀
db3>-$ new-db
database address | transaction id
--------------------------------------------+----------------------------------------------
0x7720f39c6bf077582ab89797c90ca7701ea82ea9 | dw44D6TeBRRZJ8U6fCiVvLPuAvi/B/xBSOAtYMJgUBk=
db3>-$ new-collection --addr 0x7720f39c6bf077582ab89797c90ca7701ea82ea9 --name todos --index '{"id":0, "name":"owner_idx","fields":[{"field_path":"owner","value_mode":{"Order":1}}]}'
send add collection done with tx
o6m7DHogWxaFb6jLQRu5aPzPSwgAP5JK1kBYohNiq7c=
Step 3: Running the Todo Application
Download the todo application code and open the corresponding demo folder.
git clone <https://github.com/dbpunk-labs/db3.js.git>
cd db3.js/examples/todomvc
Next, build:
yarn
yarn start
Then use a browser to open http://localhost:3000/ to see the todo application.
Code Overview
Next, we will explain the project's creation process and provide code examples of key parts.
File Overview:
├── src
│ ├── App.tsx
│ ├── base.css
│ ├── context.ts
│ ├── footer.tsx
│ ├── header.tsx
│ ├── index.tsx
│ ├── link.tsx
│ ├── logo.svg
│ ├── main_section.tsx
│ ├── reducer.ts
│ ├── todo_input.tsx
│ ├── todo_item.tsx
│ └── todo_list.tsx
Briefly explain the functions of the above files:
header: displays the application's top "what needs to be done", including the form
addTodo
for creating a new to-do item by calling operations.footer: displays aggregation information and controls, as well as a menu classification bar "all/active/completed."
main_section: displays the middle part of the to-do list.
reducer and todo_item: define the operations of CRUD and the update of operation status, which is the focus of this article.
todo_input: mainly defines the content input and the event monitoring of Enter.
Component Overview
The referencing relationship is quite complex, but don't worry; we can see that almost all other components are imported from the reducer, mainly because the reducer file defines almost all states, operations, and state change processes. The CRUD process that we focus on this time is also mainly described by the Reducer.ts file.
State, Operations, and Filtering Processes in Reducer
State and Content:
In concept, this Todo application mainly needs to define the following two parts of content:
A list of to-do items
The current filtering option (all/todo/complete)
Each to-do item needs to store the following information:
The text content of the to-do item (line 17)
A boolean value indicating whether it has been completed (line 18)
The owner of this to-do item data (line 19) (The owner concept is unique to the DB3 Network, and you can view the issue.)
The filtering process needs to be determined based on the status information of the to-do items:
An array of document lists (line 23)
A boolean value indicating whether it is loaded (line 24)
The name of the collection is stored in DB3 (line 26)
The user's wallet address (line 27) (PS. The wallet and its corresponding signature are automatically generated. For quick demo purposes, these pieces of information are currently stored directly in the browser. In the future, we will support the MetaMask wallet.)
Where to render and display under which filtering menu (line 28)
CRUD Operations
In the CRUD process, the first step is to enumerate the CRUD action
(line 31-36): INSERT
/ UPDATE
/ QUERY
/ DELETE
; the second step is that since we are not updating synchronously here, that is, the TodoState
will not be updated immediately when dispatching the action
. Therefore, we need to define which information changes asynchronously during this process (line 38-47).
Then, we can trigger asynchronous operations according to the CRUD action
(line 53-99):
INSERT
will trigger the collection
and addDoc
methods of DB3.js, complete adding the addDoc
to the corresponding db
and collection
, and then trigger the QUERY
operation accordingly;
UPDATE
will trigger the updateDoc
method of DB3.js, and the data in DB3Store
will be updated accordingly, and the size and field of the doc will also be updated accordingly. After completion, the QUERY
operation will also be triggered;
DELETE
will trigger the deleteDoc
method of DB3.js, and the data in DB3Store
will be updated accordingly. After completion, the QUERY
operation will also be triggered;
QUERY
will trigger the getDocs
method of DB3.js to list all docs, and at the same time, it will verify whether the owner
of each to-do item is the current userAddress
to filter the to-do items that belong to the current userAddress
. After filtering, it will be refreshed;
All the above-mentioned DB3.js methods (except for getDocs
) are collectively called mutations in DB3 Network. They will communicate with DB3 Network; all operation results will be recorded on the chain and cannot be tampered with.
Filtering and State Updates
As mentioned earlier, defining the filtering process is another key notion this application must fulfill. The runfilter
method (lines 103-116) is defined to filter the display based on the status of each to-do item.
The main function of the reducer is to describe the process of generating nextState
based on (previousState, action)
. Therefore, after the asynchronous operation is completed, when REFRESH
is triggered, nextState
remains unchanged, but the new todoList: resultSet
is displayed; when LOADING
and UNLOADING
are triggered, nextState remains unchanged.
The above is from the sample code of the
TodoMVC. As mentioned earlier, we will add two features in the future:
Adding support for MetaMask wallet addresses
Add network operation logs in UI
If you find our content helpful, please give us a Github ⭐️.
Reference
https://dev.to/chroline/why-the-new-firebase-web-v9-modular-sdk-is-a-game-changer-nph
https://zhuanlan.zhihu.com/p/551650121
https://redux.js.org/tutorials/fundamentals/part-3-state-actions-reducers
Posted on March 3, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.