Build a Budget App with React (Part 2 of 2)
In Part 1, we began our budget app to make our front end React framework render dummy data dynamically. When we input a transaction (description + amount) into the input field and pressed ‘Add’, the transaction rendered at the bottom of our transaction list—red for a negative transaction and green for a positive one.
Now, it’s server and database time. First, we need to create the database and tables. Install MySQL, and in a file called schema.sql define your table. The code in this file is only 7 lines. We tell MySQL which database we want to use, drop the table that’s there, and create a new table called ‘txns’ and columns ‘id’, ‘amount’, and ‘description’.
use budget;
drop table if exists txns;
create table txns (
id int primary key not null auto_increment,
amount decimal(19, 2),
description varchar(50)
);
Now we should make a server.js file. In it, require HTTP, Express, MySQL, and fs. Use the npm express docs to help you set up the server. Then, connect it with:
var connection = mysql.createConnection({
host: 'localhost',
user: 'root',
database: 'budget'
});connection.connect();
We want to make three routes. One that responds to GET requests to ‘/’ with our index.html file, one that responds to GET requests to ‘/transactions’, and one that responds to POST requests to ‘/transactions’. The route responding to a GET to ‘/transactions’ will send an array of objects in its response. That array should have this format:
var dataSet = [
{amount: -10, description: 'Chipotle'},
{amount: 200, description: 'Paycheck'},
{amount: -4.50, description: 'Coffee'}
];
The POST route will add transaction data to the database. Lucky for us, express lets us use a one-liner to serve a static file: app.use(express.static(‘./’));
‘./’ is where Express should look for our static file to serve; my index.html is in my root directory.
The GET route method will: set the status code to 200, query the database for everything in my ‘txns’ table, and send the result of the query to the client stringified. Try it on your own! Extra tips: use connection.query() to query the database and call response.end() inside the function’s callback, as it is asynchronous.
The POST route method is more involved. We will set the status code, create a data variable to store the stream of data coming from the client, push data chunks into the data variable, parse it when the data finishes streaming, add the object to our budget database, and send an empty response.
Our server is complete!
The last thing we have to do is update our app.js file with GET and POST requests to the server.
GET
Because we want data persistence, i.e. we want our transactions to be saved and render on the page when we come back to our budget, we will place our get request in the componentWillMount() function provided to us by React. This will perform our GET request before anything is rendered on the page and have our transaction data ready for us. This means that we are placing our setState() function already in componentWillMount() inside the success callback of our GET request. Connecting the client-server-database model, How does that play in to the server-side route we created?
We want our client to fetch the data at our route ‘/transactions’, which it does with an HTTP GET request to the server. When our server gets the GET request, it will pass the data the client asked for back to it. The client will receive the data and use it to set a new state with setState().
componentWillMount() {
$.get('/transactions', (data) => {
this.setState({
data: data,
total: data.reduce( (a, b) => {
return a + b.amount;
}, 0)
});
});
}
POST
Now, let’s take a look at the add() function we left unimplemented in Part 1. The POST request to the server goes in here because we want our balance to update when we click our add button. We thus want to send data to the server, post it to our database, and when that’s done, also render the sent data on our browser page.
add() takes in description and amount parameters passed up from from the Add component, which it uses in its data object as the values being sent to the server.
On success, the client gets back data
, which is a JSON string, so we must parse the data. Also, to get amount into a number we also use parseFloat() on data.amount (this was tricky). Another key aspect is that we use a variable dataArr
to store the current state’s data–this.state.data
. We then push the parsed data
object into dataArr
and update the state with the new data
and total
states.
We’re all done. Celebrate your full-stack app!
Along the way, I omit outlining testing practices using tools such as the Chrome development tools, console.logs, and Postman, which tested my server before creating my client-side HTTP requests.
I hope you enjoyed documenting your recent transactions.
Happy hacking.