Build a decentralized CRUD application using Typescript, React, and DB3.js

xutweety

xutweety

Posted on March 3, 2023

Build a decentralized CRUD application using Typescript, React, and DB3.js

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:

  1. Create: Enter a new to-do item, add the to-do item to the list, and complete the addition process by pressing Enter.

  2. Read: Listen to the document in the collection and display the list, including all to-dos, active to-dos, and completed to-dos.

  3. Update: Modify the content of the to-do item; when it is done, click it to mark it as completed.

  4. Delete: Delete the to-do items.

CRUD in the demo

(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
Enter fullscreen mode Exit fullscreen mode

After starting, you can see network activity similar to the following:

network log

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=
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Next, build:

yarn
yarn start
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

relationship of the imports

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

💖 💪 🙅 🚩
xutweety
xutweety

Posted on March 3, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related