Skip to main content

Flask: Integrating with React/Vue.js

Flask: Integrating with React/Vue.js

Integrating Flask with modern JavaScript frameworks like React or Vue.js enables developers to build dynamic, responsive web applications with a robust backend. Built on Flask’s lightweight core and leveraging Jinja2 Templating and Werkzeug WSGI, Flask serves as an API backend, while React or Vue.js handles the frontend. This tutorial explores Flask integrating with React/Vue.js, covering setup, API communication, and practical applications for full-stack development.


01. Why Integrate Flask with React/Vue.js?

Flask provides a flexible backend for creating RESTful APIs, handling authentication, and managing data, while React and Vue.js excel at building interactive, component-based user interfaces. Combining them allows developers to separate concerns, leveraging Flask’s simplicity for server-side logic and the reactivity of React/Vue.js for client-side rendering. This integration, supported by Jinja2 Templating and Werkzeug WSGI, ensures scalability and maintainability for modern web applications.

Example: Basic Flask API Setup

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/data')
def get_data():
    return jsonify({'message': 'Hello from Flask!', 'data': [1, 2, 3]})

if __name__ == '__main__':
    app.run(debug=True)

Output (visiting /api/data):

{
  "message": "Hello from Flask!",
  "data": [1, 2, 3]
}

Explanation:

  • Flask - Serves as the backend API.
  • jsonify - Returns JSON responses for frontend consumption.

02. Key Integration Techniques

Integrating Flask with React or Vue.js involves setting up a Flask API, serving the frontend, and enabling communication via HTTP requests. The table below summarizes key techniques and their applications:

Technique Description Use Case
RESTful API @app.route, jsonify Expose backend data to frontend
Frontend Setup React/Vue.js with create-react-app or vue create Build interactive UI
HTTP Requests fetch or axios Communicate between frontend and backend
CORS Handling Flask-CORS Enable cross-origin requests
Static File Serving app.static_folder Serve compiled frontend assets


2.1 Creating a RESTful API with Flask

Example: Flask API for Tasks

from flask import Flask, jsonify, request

app = Flask(__name__)

tasks = [
    {'id': 1, 'title': 'Learn Flask', 'done': False},
    {'id': 2, 'title': 'Learn React', 'done': False}
]

@app.route('/api/tasks', methods=['GET'])
def get_tasks():
    return jsonify(tasks)

@app.route('/api/tasks', methods=['POST'])
def add_task():
    task = request.get_json()
    tasks.append(task)
    return jsonify(task), 201

if __name__ == '__main__':
    app.run(debug=True)

Output (GET /api/tasks):

[
  {"id": 1, "title": "Learn Flask", "done": false},
  {"id": 2, "title": "Learn React", "done": false}
]

Explanation:

  • GET - Retrieves all tasks.
  • POST - Adds a new task to the list.

2.2 Setting Up React Frontend

Example: React App Fetching Data

// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    axios.get('http://localhost:5000/api/tasks')
      .then(response => setTasks(response.data))
      .catch(error => console.error('Error fetching tasks:', error));
  }, []);

  return (
    <div>
      <h1>Tasks</h1>
      <ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
        {tasks.map(task => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Setup Commands:

npx create-react-app my-app
cd my-app
npm install axios
npm start

Explanation:

  • axios.get - Fetches tasks from the Flask API.
  • useEffect - Loads data on component mount.

2.3 Setting Up Vue.js Frontend

Example: Vue.js App Fetching Data

// src/App.vue
<template>
  <div>
    <h1>Tasks</h1>
    <ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
      <li v-for="task in tasks" :key="task.id">{{ task.title }}</li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      tasks: []
    };
  },
  async created() {
    try {
      const response = await axios.get('http://localhost:5000/api/tasks');
      this.tasks = response.data;
    } catch (error) {
      console.error('Error fetching tasks:', error);
    }
  }
};
</script>

Setup Commands:

vue create my-app
cd my-app
npm install axios
npm run serve

Explanation:

  • axios.get - Retrieves tasks from Flask.
  • created - Fetches data when the component is created.

2.4 Handling CORS with Flask-CORS

Example: Enabling CORS

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)  # Enable CORS for all routes

@app.route('/api/data')
def get_data():
    return jsonify({'message': 'CORS-enabled data'})

if __name__ == '__main__':
    app.run(debug=True)

Output (React/Vue fetching /api/data):

{
  "message": "CORS-enabled data"
}

Explanation:

  • Flask-CORS - Allows cross-origin requests from frontend (e.g., localhost:3000).
  • Prevents CORS errors during development.

2.5 Serving Frontend from Flask

Example: Serving React Build

from flask import Flask, send_from_directory
import os

app = Flask(__name__, static_folder='frontend/build', static_url_path='/')

@app.route('/')
def serve():
    return send_from_directory(app.static_folder, 'index.html')

@app.route('/api/data')
def get_data():
    return {'message': 'Data from Flask'}

if __name__ == '__main__':
    app.run(debug=True)

Setup Commands (React):

cd frontend
npm run build
mv build ../frontend/build

Explanation:

  • static_folder - Points to the compiled frontend build.
  • send_from_directory - Serves the React/Vue.js application.

2.6 Incorrect Integration

Example: Missing CORS Configuration

from flask import Flask, jsonify

app = Flask(__name__)

@app.route('/api/data')
def get_data():
    return jsonify({'message': 'No CORS'})

if __name__ == '__main__':
    app.run(debug=True)

Output (React fetching /api/data):

Access to XMLHttpRequest at 'http://localhost:5000/api/data' from origin 'http://localhost:3000' has been blocked by CORS policy

Explanation:

  • Missing CORS configuration blocks frontend requests.
  • Solution: Install and use Flask-CORS.

03. Effective Usage

3.1 Recommended Practices

  • Use Flask-CORS during development and configure specific origins in production.

Example: Comprehensive Integration

from flask import Flask, jsonify, request
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

tasks = [
    {'id': 1, 'title': 'Learn Flask', 'done': False}
]

@app.route('/api/tasks', methods=['GET', 'POST'])
def tasks_endpoint():
    if request.method == 'GET':
        return jsonify(tasks)
    elif request.method == 'POST':
        task = request.get_json()
        tasks.append(task)
        return jsonify(task), 201

if __name__ == '__main__':
    app.run(debug=True)

React Frontend (App.js):

// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [tasks, setTasks] = useState([]);
  const [newTask, setNewTask] = useState('');

  useEffect(() => {
    axios.get('http://localhost:5000/api/tasks')
      .then(response => setTasks(response.data));
  }, []);

  const addTask = () => {
    axios.post('http://localhost:5000/api/tasks', {
      id: tasks.length + 1,
      title: newTask,
      done: false
    }).then(response => {
      setTasks([...tasks, response.data]);
      setNewTask('');
    });
  };

  return (
    <div>
      <h1>Task Manager</h1>
      <input
        value={newTask}
        onChange={e => setNewTask(e.target.value)}
        placeholder="New task"
      />
      <button onClick={addTask}>Add Task</button>
      <ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
        {tasks.map(task => (
          <li key={task.id}>{task.title}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;
  • Use axios or fetch for reliable API calls.
  • Structure Flask APIs with clear endpoints and methods.

3.2 Practices to Avoid

  • Avoid serving frontend and backend on the same port during development without CORS.

Example: Incorrect API Endpoint

from flask import Flask

app = Flask(__name__)

@app.route('/data')  # Incorrect: Non-API route
def get_data():
    return "Plain text response"

if __name__ == '__main__':
    app.run(debug=True)

Output (React fetching /data):

SyntaxError: Unexpected token P in JSON at position 0
  • Non-JSON responses break frontend parsing.
  • Solution: Use jsonify for API endpoints.

04. Common Use Cases

4.1 Task Management Application

Build a task manager with Flask backend and React/Vue.js frontend.

Example: Task Manager

from flask import Flask, jsonify, request
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

tasks = [
    {'id': 1, 'title': 'Initial Task', 'done': False}
]

@app.route('/api/tasks', methods=['GET', 'POST'])
def manage_tasks():
    if request.method == 'GET':
        return jsonify(tasks)
    elif request.method == 'POST':
        task = request.get_json()
        tasks.append(task)
        return jsonify(task), 201

if __name__ == '__main__':
    app.run(debug=True)

Vue.js Frontend (App.vue):

// src/App.vue
<template>
  <div>
    <h1>Task Manager</h1>
    <input v-model="newTask" placeholder="New task" />
    <button @click="addTask">Add Task</button>
    <ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
      <li v-for="task in tasks" :key="task.id">{{ task.title }}</li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      tasks: [],
      newTask: ''
    };
  },
  async created() {
    const response = await axios.get('http://localhost:5000/api/tasks');
    this.tasks = response.data;
  },
  methods: {
    async addTask() {
      const task = { id: this.tasks.length + 1, title: this.newTask, done: false };
      const response = await axios.post('http://localhost:5000/api/tasks', task);
      this.tasks.push(response.data);
      this.newTask = '';
    }
  }
};
</script>

Explanation:

  • Flask handles task storage and API logic.
  • Vue.js provides a reactive frontend for task management.

4.2 User Dashboard

Create a user dashboard with Flask API and React frontend.

Example: User Dashboard

from flask import Flask, jsonify
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@example.com'}
]

@app.route('/api/users')
def get_users():
    return jsonify(users)

if __name__ == '__main__':
    app.run(debug=True)

React Frontend (App.js):

// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    axios.get('http://localhost:5000/api/users')
      .then(response => setUsers(response.data));
  }, []);

  return (
    <div>
      <h1>User Dashboard</h1>
      <table class="article-table-container">
        <thead>
          <tr>
            <th>Name</th>
            <th>Email</th>
          </tr>
        </thead>
        <tbody>
          {users.map(user => (
            <tr key={user.id}>
              <td>{user.name}</td>
              <td>{user.email}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export default App;

Explanation:

  • Flask serves user data via API.
  • React displays data in a tabular, responsive format.

Conclusion

Integrating Flask with React or Vue.js, powered by Jinja2 Templating and Werkzeug WSGI, enables the creation of modern, full-stack web applications. Key takeaways:

  • Use Flask to build RESTful APIs with jsonify.
  • Leverage React/Vue.js for dynamic, component-based frontends.
  • Enable CORS with Flask-CORS for seamless communication.
  • Avoid common pitfalls like missing CORS or incorrect response formats.

With this integration, you can build scalable, interactive web applications that combine the strengths of Flask’s backend and React/Vue.js’s frontend capabilities!

Comments