How I solved my code issues while building a blockchain Donation App with a token I created?
Introduction
I am Amara, a software developer and a budding blockchain developer. I have always belonged to the school of thought that Blockchain is a game changer in every sector.
To get going, I had to get my hands dirty by building projects, so I decided to build a donation blockchain app that will enable people to donate using my tokens to Children in Africa that needed to get back to school.
The blockchain donation App
I don't want to bore you with the entire process but will be going ahead to take you where I faced some issues and solved them. I believe with basic knowledge of blockchain, react and web3js you will just be fine in understanding the entire process. I wouldn't be making the GitHub link public due to the fact that some developers got blown away and we will be launching soon, so we decided to keep it private till after launching, it becomes open source.
The Entire Setup
Solidity: Solidity is a programming language used to write smart contracts for the Ethereum blockchain. You would need to be familiar with Solidity to create the smart contract that will handle donations in your app.
Remix IDE: Remix is a web-based integrated development environment (IDE) for writing, testing, and deploying smart contracts. You can use Remix to write your smart contract code and test it on a local blockchain.
Truffle: Truffle is a development framework that makes it easier to write, test, and deploy smart contracts. Truffle provides tools for compiling Solidity code, deploying contracts to a blockchain, and interacting with deployed contracts.
Ganache: Ganache is a personal blockchain for Ethereum development. You can use Ganache to create a local blockchain for testing your smart contracts.
Web3.js: Web3.js is a JavaScript library for interacting with the Ethereum blockchain. You can use Web3.js to connect to a blockchain, send transactions, and interact with smart contracts from a web application.
React: React is a JavaScript library for building user interfaces. You can use React to create the FrontEnd of your blockchain donation app.
MetaMask: MetaMask is a browser extension that provides a wallet for storing and managing Ethereum accounts. You can use MetaMask to connect to the Rinkeby testnet and send testnet Ether and tokens.
Rinkeby testnet: Rinkeby is a public Ethereum testnet that enables developers to test their applications with fake Ether and tokens. You can use Rinkeby to test your smart contract and frontend code before deploying to the main Ethereum network.
Infura: Infura is a web3 provider that enables you to connect to the Ethereum network without running a local node. You can use Infura to deploy your smart contract and connect to the Rinkeby testnet from your frontend code.
GitHub: GitHub is a web-based platform for hosting and sharing code repositories. You can use GitHub to store and manage the code for your blockchain donation app.
By using these technologies and tools, you can create a blockchain donation app that enables users to donate tokens securely and transparently on the Rinkeby testnet.
Using the useState hook to manage the state of your app
Having created by token within an hour and launching it on the Rinkeby testnet, I had to move ahead into integration and deployment.
After doing some research and brainstorming, I decided to use the useState hook to manage the state of my app. The useState hook is a built-in React hook that allows you to declare state variables in functional components.
I started by creating a new React project and began writing code to build a simple form. The form would allow users to enter their name, email, and the amount they would like to donate.
You declared a state variable called formData
and set its initial value to an empty object using the useState hook.
import React, { useState } from 'react';
function App() {
const [formData, setFormData] = useState({});
// ...
}
Next, I wrote a function called handleChange
to update the formData
state whenever the user entered data into the form. I passed this function as a callback to the onChange event of each input field in the form.
import React, { useState } from 'react';
function App() {
const [formData, setFormData] = useState({});
function handleChange(event) {
const { name, value } = event.target;
setFormData(prevState => ({ ...prevState, [name]: value }));
}
return (
<form>
<label>
Name:
<input type="text" name="name" onChange={handleChange} />
</label>
<label>
Email:
<input type="email" name="email" onChange={handleChange} />
</label>
<label>
Amount:
<input type="number" name="amount" onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
I tested my form and noticed that the handleChange
function was not updating the formData
state as expected. I inspected the console and saw that you were getting an error message that reads:
"TypeError: Cannot read property 'target' of undefined."
I realized that the problem was with the handleChange
function. It was trying to access the event.target
property, but the event
parameter was undefined. I went back to the code and added a check to ensure that the event
parameter was defined before accessing its properties.
function handleChange(event) {
if (event) {
const { name, value } = event.target;
setFormData(prevState => ({ ...prevState, [name]: value }));
}
}
With this change, the form started working correctly. The handleChange
function was now properly updating the formData
state whenever the user entered data into the form.
Next, I decided to add some conditional rendering to the form. I wanted to display a success message when the user submitted the form successfully. I updated your handleSubmit
function to update the state variable formSubmitted
to true and render the success message.
function handleSubmit(event) {
event.preventDefault();
setFormSubmitted(true);
}
return (
<div>
<form onSubmit={handleSubmit}>
// ...
<button type="submit">Submit</button>
</form>
{formSubmitted && (
<p>Thank you for your donation!</p>
)}
</div>
);
I tested my app again and noticed that the success message was not displayed after submitting the form. I inspected the console and saw that I was getting an error message that reads:
"ReferenceError: setFormSubmitted is not defined."
I realized that the problem was with the handleSubmit
function. It was trying to call a function called, setFormSubmitted
but I had not declared this function anywhere. I went back to the code and added the setFormSubmitted
function using the useState hook, just like you did with the formData
state.
function App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
function handleChange(event) {
if (event) {
const { name, value } = event.target;
setFormData(prevState => ({ ...prevState, [name]: value }));
}
}
function handleSubmit(event) {
event.preventDefault();
setFormSubmitted(true);
}
return (
<div>
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" name="name" onChange={handleChange} />
</label>
<label>
Email:
<input type="email" name="email" onChange={handleChange} />
</label>
<label>
Amount:
<input type="number" name="amount" onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
{formSubmitted && (
<p>Thank you for your donation!</p>
)}
</div>
);
}
With this change, my app was working perfectly. The handleChange
function was updating the formData
state as expected, and the handleSubmit
function was updating the formSubmitted
state and display the success message when the user submitted the form.
After successfully implementing the useState hook to manage form state in my blockchain donation app, I continued to make progress towards my goal. I connected my app to the blockchain network using web3.js and created a smart contract that would enable users to make donations and track their transactions on the blockchain.
As I tested the app, I noticed a new issue. When users made donations, the app would display a success message, but it wouldn't update the total amount of donations received. I realized that I needed to use the useEffect hook to fetch data from the blockchain and update the donation total whenever a new donation was made.
I started by adding a new state variable called totalDonations
using the useState hook.
function App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
const [totalDonations, setTotalDonations] = useState(0);
// ...
}
Then I added a new useEffect hook that would fetch the total amount of donations from the smart contract whenever a new donation was made.
function App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
const [totalDonations, setTotalDonations] = useState(0);
useEffect(() => {
async function getTotalDonations() {
// Get the total amount of donations from the smart contract
const contract = new web3.eth.Contract(contractAbi, contractAddress);
const totalDonations = await contract.methods.getTotalDonations().call();
setTotalDonations(totalDonations);
}
getTotalDonations();
}, [formSubmitted]);
// ...
}
After successfully implementing the useState hook to manage form state in your blockchain donation app, you continued to make progress towards your goal. You connected your app to the blockchain network using web3.js and created a smart contract that would enable users to make donations and track their transactions on the blockchain.
As you tested your app, you noticed a new issue. When users made donations, the app would display a success message, but it wouldn't update the total amount of donations received. You realized that you needed to use the useEffect hook to fetch data from the blockchain and update the donation total whenever a new donation was made.
You started by adding a new state variable called totalDonations
using the useState hook.
jsxCopy codefunction App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
const [totalDonations, setTotalDonations] = useState(0);
// ...
}
Then you added a new useEffect hook that would fetch the total amount of donations from the smart contract whenever a new donation was made.
jsxCopy codefunction App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
const [totalDonations, setTotalDonations] = useState(0);
useEffect(() => {
async function getTotalDonations() {
// Get the total amount of donations from the smart contract
const contract = new web3.eth.Contract(contractAbi, contractAddress);
const totalDonations = await contract.methods.getTotalDonations().call();
setTotalDonations(totalDonations);
}
getTotalDonations();
}, [formSubmitted]);
// ...
}
In this code snippet, I created a new function called getTotalDonations
that uses web3.js to interact with the smart contract and get the total amount of donations. I called this function inside a useEffect hook that runs whenever formSubmitted
changes. This way, whenever a new donation is made, the useEffect hook will update the totalDonations
state and cause the app to display the updated donation total.
As you continued to refine your blockchain donation app, I encountered new challenges and opportunities to improve the code. One of the challenges I faced was dealing with asynchronous data loading when fetching data from the blockchain. I realized that the useEffect hook I was using to fetch data was causing unnecessary re-renders of the components, which slowed down the app and made it less responsive.
To address this issue, I turned to the useCallback hook, which enables one to memoize functions and prevent unnecessary re-renders. I started by creating a new function called fetchTotalDonations
using the useCallback hook.
function App() {
const [formData, setFormData] = useState({});
const [formSubmitted, setFormSubmitted] = useState(false);
const [totalDonations, setTotalDonations] = useState(0);
const fetchTotalDonations = useCallback(async () => {
// Get the total amount of donations from the smart contract
const contract = new web3.eth.Contract(contractAbi, contractAddress);
const totalDonations = await contract.methods.getTotalDonations().call();
setTotalDonations(totalDonations);
}, [setTotalDonations]);
useEffect(() => {
fetchTotalDonations();
}, [fetchTotalDonations]);
// ...
}
In this code snippet, I created a new function called fetchTotalDonations
using the useCallback hook. This function uses web3.js to interact with the smart contract and get the total amount of donations. By wrapping this function with the useCallback hook, I ensured that it would only be re-created when the setTotalDonations
function changed. This prevented unnecessary re-renders of your components and made the app more responsive.
I also updated the useEffect hook to use the fetchTotalDonations
function instead of defining the function inside the hook. This ensured that the useEffect hook would only re-run when the fetchTotalDonations
function changes.
With this change, the app was working perfectly. Users could make donations and see the updated donation total in real-time. I continued to refine the app and implement new features, such as a progress bar that displayed the percentage of the donation goal reached, and a social sharing button that enabled users to share their donations on social media. a leaderboard that displayed the top donors and a transaction history that showed all donations made on the blockchain.
Conclusion
Throughout my journey of building the blockchain donation app, the useState, useCallback and useEffect hooks were essential tools that helped me manage the state and update the app in response to user actions and external data sources. By leveraging the power of these hooks and other React features, I was able to create a dynamic and user-friendly app that fulfilled your vision of enabling secure and transparent donations on the blockchain.
What I learned from this project and Challenges 🤗
You never know how much you know until you put in the work and much practice.
Thanks for reading! ❤️ This article is the #DebuggingFeb Eleftheria Batsou challenge. NB: This article was published as the ##DebuggingFeb article for the Hashnode writeathon.
If you liked this article please follow me on Hashnode for my latest articles. I'm tweeting my journey on Twitter daily, this way to my LinkedIn . Hasnode
I share my knowledge on,
🌐 Web Development
✍️ Content Creation
💼 Career Development
🦾Personal Growth
BlockChain
And more!
References
React useState:React useState
React useEffect: React useEffect
React useCallback: React useCallback
Launching a decentralized App: Blog