Integrating React with Symfony: Build a Modern Task Manager
Welcome back to my blog! If you've been following my Symfony series, you built a Task Manager CRUD app with Twig templates. But let's face it—those basic HTML templates can feel a bit dated. To give your app a modern, interactive UI, let's integrate React with Symfony. React will handle the frontend, while Symfony powers the backend via a REST API. This guide is beginner-friendly, assuming basic PHP and JavaScript knowledge. If you're coming from Laravel, I'll draw parallels to make it easier.
By the end, you'll have a sleek Task Manager where users can create, view, update, and delete tasks using React's dynamic components, talking to Symfony's API. Let's dive in!
Why React with Symfony?
Symfony is a robust PHP framework for building APIs and handling backend logic, similar to Laravel. React, a JavaScript library, excels at creating interactive, component-based UIs. Combining them gives you:
- Separation of Concerns: Symfony handles data and logic; React manages the UI.
- Modern UI: React's components make your app feel like a single-page application (SPA).
- Scalability: Symfony's API Platform makes it easy to expose data to any frontend.
- Flexibility: Use React for the whole app or just parts, keeping Twig for static pages.
Laravel Users: Think of Symfony as Laravel's API routes + Eloquent, but with more explicit configuration. React replaces Blade for dynamic rendering.
Prerequisites
You'll need:
- Symfony 7.1 project (from my previous post, with Doctrine and the Task entity).
- Node.js and npm (for React).
- MySQL database (configured in
.env). - Basic PHP, JavaScript, and React knowledge (I'll keep it simple).
Assumption: You have a Symfony project with a Task entity (name, description, dueDate, completed) and database set up.
Step 1: Set Up Symfony as an API Backend
We'll use API Platform to turn your Symfony app into a REST API. This exposes your Task entity as endpoints (e.g., /api/tasks) that React can consume.
Install API Platform
Run:
composer require api
This installs API Platform and configures routes for /api.
Expose the Task Entity
Update src/Entity/Task.php to make it an API resource:
// src/Entity/Task.php
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\Metadata\Put;
use ApiPlatform\Metadata\Delete;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
#[ApiResource(operations: [
new Get(),
new GetCollection(),
new Post(),
new Put(),
new Delete()
])]
#[ORM\Entity]
class Task
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(type: Types::TEXT)]
private ?string $description = null;
#[ORM\Column(type: Types::DATETIME_MUTABLE)]
private ?\DateTimeInterface $dueDate = null;
#[ORM\Column]
private ?bool $completed = false;
// Getters and setters...
}
This creates endpoints:
GET /api/tasks: List all tasks.GET /api/tasks/{id}: Get a task.POST /api/tasks: Create a task.PUT /api/tasks/{id}: Update a task.DELETE /api/tasks/{id}: Delete a task.
Test it: Run symfony server:start and visit http://localhost:8000/api. You’ll see API Platform’s UI.
Troubleshooting: Ensure your database is set up (php bin/console doctrine:migrations:migrate). If endpoints don’t work, check var/log/dev.log.
Step 2: Set Up the React Frontend
We’ll create a separate React app to consume the Symfony API. For simplicity, we’ll use Create React App.
Create the React App
In a new folder (outside your Symfony project):
npx create-react-app task-manager-frontend
cd task-manager-frontend
npm install axios bootstrap
Axios will handle API calls; Bootstrap adds quick styling.
Configure CORS
Allow React (running on :3000) to talk to Symfony (:8000):
Edit config/packages/nelmio_cors.yaml (create if missing):
nelmio_cors:
defaults:
origin_regex: true
allow_origin: ['^http://localhost:[0-9]+']
allow_methods: ['GET', 'POST', 'PUT', 'DELETE']
allow_headers: ['Content-Type', 'Authorization']
max_age: 3600
Install if needed:
composer require nelmio/cors-bundle
Create React Components
Replace src/App.js with a Task Manager component:
// src/App.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import 'bootstrap/dist/css/bootstrap.min.css';
function App() {
const [tasks, setTasks] = useState([]);
const [formData, setFormData] = useState({
name: '',
description: '',
dueDate: '',
completed: false
});
const [editingTask, setEditingTask] = useState(null);
useEffect(() => {
fetchTasks();
}, []);
const fetchTasks = async () => {
const res = await axios.get('http://localhost:8000/api/tasks');
setTasks(res.data['hydra:member']); // API Platform wraps data
};
const handleInputChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData({ ...formData, [name]: type === 'checkbox' ? checked : value });
};
const handleSubmit = async (e) => {
e.preventDefault();
const payload = {
...formData,
dueDate: new Date(formData.dueDate).toISOString()
};
if (editingTask) {
await axios.put(`http://localhost:8000/api/tasks/${editingTask.id}`, payload);
setEditingTask(null);
} else {
await axios.post('http://localhost:8000/api/tasks', payload);
}
setFormData({ name: '', description: '', dueDate: '', completed: false });
fetchTasks();
};
const handleEdit = (task) => {
setEditingTask(task);
setFormData({
name: task.name,
description: task.description,
dueDate: task.dueDate.split('T')[0],
completed: task.completed
});
};
const handleDelete = async (id) => {
if (window.confirm('Delete task?')) {
await axios.delete(`http://localhost:8000/api/tasks/${id}`);
fetchTasks();
}
};
return (
Task Manager
{tasks.map(task => (
{task.name}
{task.description}
Due: {new Date(task.dueDate).toLocaleDateString()}
{task.completed && Completed}
))}
);
}
export default App;
This component handles all CRUD operations with a modern Bootstrap UI.
Step 3: Configure React to Talk to Symfony
Add a proxy to avoid CORS issues during development. In task-manager-frontend/package.json, add:
"proxy": "http://localhost:8000"
This forwards API requests from React (:3000) to Symfony (:8000).
Step 4: Run Both Apps
In your Symfony project:
symfony server:start
In your React project:
npm start
Visit http://localhost:3000. You’ll see a modern Task Manager with a form to add/edit tasks and a card-based list.
Troubleshooting:
- API errors? Check
var/log/dev.logor React’s console. - Data not loading? Ensure
hydra:memberis accessed (API Platform’s format). - CORS issues? Verify
nelmio_cors.yaml.
Step 5: Enhance the UI (Optional)
Want an even sleeker look? Add Tailwind CSS to React:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Update tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{js,jsx,ts,tsx}"],
theme: { extend: {} },
plugins: [],
}
Add to src/index.css:
@tailwind base;
@tailwind components;
@tailwind utilities;
Replace Bootstrap classes in App.js with Tailwind (e.g., className="bg-white p-6 rounded-lg shadow-md").
Step 6: Keep Symfony Controllers (Optional)
If you want to keep some Twig pages (e.g., for admin views), retain your TaskController.php from the previous post. Symfony can serve both APIs and Twig templates. For example, keep /tasks for Twig and use /api/tasks for React.
Best Practices
- API Security: Add JWT authentication (
composer require lexik/jwt-authentication-bundle). - Performance: Minify React with
npm run build. Cache API responses in Symfony. - Testing: Use PHPUnit for Symfony, Jest for React.
- Deployment: Host Symfony on a PHP server (e.g., Heroku), React on Netlify or Vercel.
- Resources:
- Symfony Frontend Docs
- API Platform Docs
- React Docs
- SymfonyCasts: "API Platform" course
Conclusion
You’ve upgraded your Task Manager to a modern, React-powered app with Symfony’s API backend! You learned:
- Setting up Symfony as a REST API with API Platform.
- Building a React frontend with Bootstrap.
- Connecting the two for a dynamic CRUD app.
Next steps: Add authentication, pagination, or real-time updates with WebSockets. Share your app in the comments, and happy coding!
Comments
Post a Comment