Single Page Applications deliver superior user experience. React + Laravel combines powerful frontend with robust backend. At ZIRA Software, this stack powers e-commerce and SaaS platforms handling millions of requests.
Architecture Overview
React frontend (SPA):
- Component-based UI
- Client-side routing
- State management
- API communication
Laravel backend (API):
- RESTful endpoints
- Authentication
- Business logic
- Database operations
Project Setup
Create Laravel API:
laravel new my-app-api
cd my-app-api
# Install Laravel Passport for API auth
composer require laravel/passport
php artisan passport:install
Create React frontend:
npx create-react-app my-app-frontend
cd my-app-frontend
npm install axios react-router-dom
Laravel API Setup
Configure CORS:
composer require fruitcake/laravel-cors
// config/cors.php
return [
'paths' => ['api/*'],
'allowed_origins' => ['http://localhost:3000'],
'allowed_methods' => ['*'],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];
API routes:
// routes/api.php
Route::post('/login', 'AuthController@login');
Route::post('/register', 'AuthController@register');
Route::middleware('auth:api')->group(function () {
Route::get('/user', 'AuthController@user');
Route::apiResource('posts', 'PostController');
});
API Controller:
// app/Http/Controllers/Api/PostController.php
namespace App\Http\Controllers\Api;
use App\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
return Post::with('user')->latest()->paginate(15);
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
]);
$post = $request->user()->posts()->create($validated);
return response()->json($post, 201);
}
public function show(Post $post)
{
return $post->load('user');
}
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
$validated = $request->validate([
'title' => 'required|max:255',
'content' => 'required',
]);
$post->update($validated);
return response()->json($post);
}
public function destroy(Post $post)
{
$this->authorize('delete', $post);
$post->delete();
return response()->json(null, 204);
}
}
React Frontend
API client:
// src/api.js
import axios from 'axios';
const api = axios.create({
baseURL: 'http://localhost:8000/api',
withCredentials: true,
});
// Add token to requests
api.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default api;
Authentication:
// src/components/Login.js
import React, { useState } from 'react';
import api from '../api';
function Login({ onLogin }) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await api.post('/login', { email, password });
localStorage.setItem('token', response.data.token);
onLogin(response.data.user);
} catch (error) {
console.error('Login failed:', error);
}
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e)=> setEmail(e.target.value)}
placeholder="Email"
required
/>
<input
type="password"
value={password}
onChange={(e)=> setPassword(e.target.value)}
placeholder="Password"
required
/>
<button type="submit">Login</button>
</form>
);
}
export default Login;
Posts component:
// src/components/Posts.js
import React, { useState, useEffect } from 'react';
import api from '../api';
function Posts() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchPosts();
}, []);
const fetchPosts = async () => {
try {
const response = await api.get('/posts');
setPosts(response.data.data);
} catch (error) {
console.error('Error fetching posts:', error);
} finally {
setLoading(false);
}
};
if (loading) return <div>Loading...</div>;
return (
<div>
<h2>Posts</h2>
{posts.map((post) => (
<article key={post.id}>
<h3>{post.title}</h3>
<p>{post.content}</p>
<small>By {post.user.name}</small>
</article>
))}
</div>
);
}
export default Posts;
State Management
Context API for auth:
// src/contexts/AuthContext.js
import React, { createContext, useState, useContext } from 'react';
const AuthContext = createContext();
export const useAuth = () => useContext(AuthContext);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const login = (userData) => setUser(userData);
const logout = () => {
localStorage.removeItem('token');
setUser(null);
};
return (
<AuthContext.Provider value={{ user, login, logout }}>
{children}
</AuthContext.Provider>
);
}
Deployment
Laravel (API):
# Deploy to server
composer install --optimize-autoloader --no-dev
php artisan config:cache
php artisan route:cache
React (Frontend):
# Build for production
npm run build
# Deploy build folder to CDN or static hosting
Conclusion
React + Laravel creates powerful, scalable SPAs. Clear separation enables independent scaling and deployment.
Building a modern web application? Contact ZIRA Software for React + Laravel development.