WittCode💻

Connect a Custom React App to Flask

By

Learn how to build a React app from scratch and connect it to a Python Flask API server. We will use Webpack to build the React bundle and proxy requests to the Flask server.

Table of Contents 📖

Project Architecture

Image

Environment Variables

ENV=development

WEBPACK_DEV_SERVER_PORT=1234
WEBPACK_DEV_SERVER_HOST=127.0.0.1
WEBPACK_DEV_SERVER_URL=http://127.0.0.1:1234

FLASK_PORT=1235
FLASK_HOST=127.0.0.1
FLASK_URL=http://127.0.0.1:1235

React Project Initialization & Installing React

To begin, lets initialize our project as an ES6 npm project.

npm init es6 -y

Now lets install React. React is just a library, so we can install it with npm.

npm i react

We will now need to install ReactDOM. ReactDOM is a package that acts as glue between React and the DOM.

npm i react-dom

Installing Webpack

Lets now install our module bundler Webpack as a development dependency. Webpack will transpile our React code to JavaScript that the browser understands.

npm i webpack -D

We also need to install the package webpack-cli (webpack command line interface).

npm i webpack-cli -D

This package provides a set of commands to increase speed/efficiency when setting up a custom webpack project. We also want to install the package webpack-dev-server.

npm i webpack-dev-server -D

This package gives us a web server to serve up our project and live reload it whenever changes are made.

Installing Babel Loader and Presets

To handle React code with Webpack, we need to install a loader called babel loader along with some other Babel dependencies.

npm i @babel/preset-env @babel/preset-react babel-loader -D

A loader is a function that Webpack passes code through to perform some sort of transformation. The Babel loader is a Webpack loader that transpiles JavaScript code. Babel presets are used to configure the Babel transipler.

  • @babel/preset-env - Allows us to use the latest JavaScript.
  • @babel/preset-react - Handles React code.

Handling HTML

Now lets create the HTML file to house our React app. We can do this using the html-webpack-plugin.

npm i html-webpack-plugin -D

A Webpack plugin interacts with the Webpack lifecycle. The html-webpack-plugin creates an HTML file to place our bundled JavaScript code into.

Configuring Webpack

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const dotenv = require('dotenv');

// Use dotenv to get the environment variables
dotenv.config({ path: path.resolve(__dirname, '../', '.env')});
const WEBPACK_DEV_SERVER_HOST = process.env.WEBPACK_DEV_SERVER_HOST;
const WEBPACK_DEV_SERVER_PORT = process.env.WEBPACK_DEV_SERVER_PORT;
const FLASK_URL = process.env.FLASK_URL;

module.exports = {
  mode: 'development',
  target: 'web',
  entry: './src/index.jsx',
  // Bundled code
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ],
  // Configure the webpack development server
  devServer: {
    static: path.resolve(__dirname, 'dist'),
    host: WEBPACK_DEV_SERVER_HOST,
    port: WEBPACK_DEV_SERVER_PORT,
    // Proxy api requests to the Flask server
    proxy: [
      {
        context: ['/api'],
        target: FLASK_URL
      }
    ]
  },
  // Pass JavaScript files through the Babel transpiler
  module: {
    rules: [
      {
        test: /.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              ['@babel/preset-react', {'runtime': 'automatic'}],
            ]
          }
        }
      }
    ]
  },
  // Resolve .js and .jsx files
  resolve: {
    extensions: ['.js', '.jsx']
  }
};

Coding the React App

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
import {createRoot} from 'react-dom/client';
import App from './components/App';

const root = createRoot(document.getElementById('root'));
root.render(<App />);
import {useEffect, useState} from "react";

export default function App() {
  const [users, setUsers] = useState([]);
  const [loadedUsers, setLoadedUsers] = useState(false);

  // Make an API call to the Flask server
  useEffect(() => {
    // Handle unmounting
    const abortController = new AbortController();
    const signal = abortController.signal;

    fetch('/api/users', {signal})
      .then(response => response.json())
      .then(data => {
        setUsers(data);
      })
      .catch(error => {
        console.error('Error fetching users:', error);
      })
      .finally(() => {
        setLoadedUsers(true);
      });
  }, []);

  // Loop through the users and display them
  return (
    <div>
      <h1>Registered Users:</h1>
      {loadedUsers ? users.map(user => <h3 key={user.id}>{user.username}</h3>) : 'Loading...'}
    </div>
  );
}

npm Start Script

"start": "webpack-dev-server --open --config webpack.config.cjs"

Python Flask Project

python3 -m venv .venv
source .venv/bin/activate
pip install Flask python-dotenv py-mon
from flask import Flask, Response
import json
from dotenv import load_dotenv
import os

# Take the environment variables from .env file
load_dotenv()
FLASK_HOST = os.environ.get("FLASK_HOST")
FLASK_PORT = os.environ.get("FLASK_PORT")

# Create Flask app
app = Flask(__name__)

# API endpoint to serve up users
@app.route("/api/users")
def users():
  users = [
    {"username": "WittCode", "id": 1}, 
    {"username": "Greg", "id": 2}, 
    {"username": "Sabin", "id": 3}, 
    {"username": "Mike", "id": 4}, 
    {"username": "Spencer", "id": 5},
    {"username": "Alex", "id": 6},
    {"username": "Sam", "id": 7},
  ]
  # Return a JSON response
  return Response(json.dumps(users), mimetype="application/json")

# Run the application at the provided host and port
if __name__ == "__main__":
  app.run(host=FLASK_HOST, port=FLASK_PORT)

Running the App

npm start
<i> [webpack-dev-server] [HPM] Proxy created: /api  -> http://127.0.0.1:1235
<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://127.0.0.1:1234/
python3 ./server.py
* Running on http://127.0.0.1:1235
Connect a Custom React App to Flask