Building a Full-Stack App with React, Express, and Chakra UI
Getting Started
Before diving into this tutorial, ensure you have a solid understanding of basic JavaScript concepts and familiarity with ES6 syntax. You should also have experience with React, including concepts like states, components, and renders. Additionally, you’ll need to be familiar with REST APIs, relational databases, and Node.js and Express.js for building a web server app.
Laying the Groundwork
Before starting any new project, it’s essential to plan out your features and workflow. Let’s outline how our app, called “Photato,” will work. Our app will have two main parts:
- A client-side React app that lets users upload photos through their browser.
- A server-side API that receives photo uploads, stores them, and allows us to query and display all uploaded photos.
Setting Up the Frontend
We’ll start by creating our frontend React app using create-react-app
. We’ll also use Chakra UI for component styling, which allows us to customize its look and feel through theming easily.
npx create-react-app photato-client
Setting Up the Backend
For our backend API, we’ll create a new file and install the necessary dependencies, including Express and Sequelize.
npm init -y
npm install express sequelize mysql2
We’ll also set up a .babelrc
file to enable writing our app using the latest ES6 syntax transpiled through Babel.
{
"presets": ["@babel/preset-env"]
}
Building the Photo Gallery
We’ll start by creating an App.js
file and filling it with code that simplifies our entry component and delegates the actual logic to another container named AppContainer
.
import React from 'eact';
import AppContainer from './AppContainer';
function App() {
return (
<div>
<AppContainer />
</div>
);
}
export default App;
We’ll then create a Header
component that wraps all its children in a Chakra UI Flex component, and a PhotoGallery
component that renders a gallery view of uploaded photos.
import { Box, Flex } from '@chakra-ui/react';
function Header({ children }) {
return (
<Flex justify="space-between" align="center">
{children}
</Flex>
);
}
export default Header;
Handling File Uploads
We’ll use the Multer package to handle file uploads, which makes it super easy to accept and store files.
npm install multer
We’ll add a new POST request endpoint that uses the upload middleware to handle file uploads and save the file details in the database.
const express = require('express');
const multer = require('multer');
const upload = multer({ dest: './uploads/' });
const app = express();
app.post('/api/upload', upload.single('photo'), async (req, res) => {
// Save the file details in the database
res.json({ message: 'Photo uploaded successfully' });
});
Connecting the Frontend and Backend
We’ll use the browser’s Fetch API to talk to our server app from the React app. We’ll create a new file that encapsulates our server communication and adds functions to get photos and upload photos.
const api = {
getPhotos: async () => {
const response = await fetch('/api/photos');
return response.json();
},
uploadPhoto: async (file) => {
const formData = new FormData();
formData.append('photo', file);
const response = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
return response.json();
},
};
export default api;
Finishing Touches
Finally, we’ll add some UX improvements, such as displaying a toast notification when a photo is uploaded successfully or unsuccessfully, and implementing a full-screen version of the gallery using the react-images package.
npm install react-images
Note: What we’ve built throughout this journey is a complete and functional app, but there’s still room for improvement. Architecture, file-folder structure, testability – all of these things should be considered for refactoring both our client- and server-side apps.