Building Full-Stack React Apps with Bolt.new
Create complete React applications with backend integration using Bolt.new
Prerequisites
Building Your First React App with Bolt.new
Introduction
React is one of the most popular JavaScript frameworks for building user interfaces, and Bolt.new makes it incredibly easy to create React applications without any setup. In this tutorial, you'll build a complete task management application while learning React fundamentals and Bolt.new best practices.
What You'll Learn
- Creating React applications with Bolt.new
- Component-based architecture
- State management with hooks
- Styling with Tailwind CSS
- Adding interactivity and animations
- Deploying your React app
Prerequisites
- Basic understanding of JavaScript
- Familiarity with HTML and CSS
- Completion of "Getting Started with Bolt.new" tutorial
Project Overview: Task Manager App
We'll build a feature-rich task manager with:
- Add, edit, and delete tasks
- Mark tasks as complete
- Filter tasks by status
- Persist data in local storage
- Responsive design
- Smooth animations
Step 1: Creating the React Project
Initial Setup
In Bolt.new, enter this prompt:
Create a React task manager app with the following features:
- Add new tasks with a form
- Display tasks in a list
- Mark tasks as complete/incomplete
- Delete tasks
- Use modern React with functional components and hooks
- Style with Tailwind CSS for a clean, modern design
- Include a header with the app title
Understanding the Generated Structure
Bolt.new will create a React project with this structure:
├── src/
│ ├── App.jsx
│ ├── components/
│ │ ├── TaskForm.jsx
│ │ ├── TaskList.jsx
│ │ └── TaskItem.jsx
│ ├── index.css
│ └── main.jsx
├── index.html
├── package.json
└── vite.config.js
Examining the Main App Component
src/App.jsx:
import React, { useState } from 'react';
import TaskForm from './components/TaskForm';
import TaskList from './components/TaskList';
function App() {
const [tasks, setTasks] = useState([]);
const addTask = (taskText) => {
const newTask = {
id: Date.now(),
text: taskText,
completed: false,
createdAt: new Date().toISOString()
};
setTasks([...tasks, newTask]);
};
const toggleTask = (id) => {
setTasks(tasks.map(task =>
task.id === id ? { ...task, completed: !task.completed } : task
));
};
const deleteTask = (id) => {
setTasks(tasks.filter(task => task.id !== id));
};
return (
<div className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4 py-8 max-w-2xl">
<header className="text-center mb-8">
<h1 className="text-4xl font-bold text-gray-800 mb-2">
Task Manager
</h1>
<p className="text-gray-600">
Stay organized and productive
</p>
</header>
<TaskForm onAddTask={addTask} />
<TaskList
tasks={tasks}
onToggleTask={toggleTask}
onDeleteTask={deleteTask}
/>
</div>
</div>
);
}
export default App;
Step 2: Understanding React Components
The TaskForm Component
src/components/TaskForm.jsx:
import React, { useState } from 'react';
function TaskForm({ onAddTask }) {
const [inputValue, setInputValue] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (inputValue.trim()) {
onAddTask(inputValue.trim());
setInputValue('');
}
};
return (
<form onSubmit={handleSubmit} className="mb-6">
<div className="flex gap-2">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
placeholder="Add a new task..."
className="flex-1 px-4 py-2 border border-gray-300 rounded-lg
focus:outline-none focus:ring-2 focus:ring-blue-500"
/>
<button
type="submit"
className="px-6 py-2 bg-blue-500 text-white rounded-lg
hover:bg-blue-600 transition-colors duration-200"
>
Add Task
</button>
</div>
</form>
);
}
export default TaskForm;
Key React Concepts Demonstrated
- Functional Components: Modern React uses functions instead of classes
- Props:
onAddTask
is passed from parent to child - useState Hook: Manages local component state
- Event Handling: Form submission and input changes
- Conditional Rendering: Only adds non-empty tasks
Step 3: Adding Advanced Features
Adding Task Filtering
Let's enhance our app with filtering capabilities. Add this prompt:
Add task filtering to the app:
- Add filter buttons for All, Active, and Completed tasks
- Show task count for each filter
- Highlight the active filter
- Maintain the current modern design
Updated App Component with Filtering
function App() {
const [tasks, setTasks] = useState([]);
const [filter, setFilter] = useState('all');
// ... previous methods ...
const filteredTasks = tasks.filter(task => {
if (filter === 'active') return !task.completed;
if (filter === 'completed') return task.completed;
return true;
});
const taskCounts = {
all: tasks.length,
active: tasks.filter(t => !t.completed).length,
completed: tasks.filter(t => t.completed).length
};
return (
<div className="min-h-screen bg-gray-50">
<div className="container mx-auto px-4 py-8 max-w-2xl">
{/* Header */}
<TaskForm onAddTask={addTask} />
{/* Filter Buttons */}
<div className="flex gap-2 mb-4">
{['all', 'active', 'completed'].map(filterType => (
<button
key={filterType}
onClick={() => setFilter(filterType)}
className={`px-4 py-2 rounded-lg capitalize transition-colors
${filter === filterType
? 'bg-blue-500 text-white'
: 'bg-white text-gray-700 hover:bg-gray-100'
}`}
>
{filterType} ({taskCounts[filterType]})
</button>
))}
</div>
<TaskList
tasks={filteredTasks}
onToggleTask={toggleTask}
onDeleteTask={deleteTask}
/>
</div>
</div>
);
}
Step 4: Adding Local Storage Persistence
Implementing Data Persistence
Add this prompt to Bolt.new:
Add local storage to persist tasks:
- Save tasks to localStorage whenever they change
- Load tasks from localStorage when the app starts
- Handle edge cases gracefully
Enhanced App with Persistence
import React, { useState, useEffect } from 'react';
function App() {
const [tasks, setTasks] = useState(() => {
// Load tasks from localStorage on initial render
const savedTasks = localStorage.getItem('tasks');
return savedTasks ? JSON.parse(savedTasks) : [];
});
// Save tasks to localStorage whenever they change
useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(tasks));
}, [tasks]);
// ... rest of the component
}
Understanding useEffect
The useEffect
hook:
- Runs side effects in functional components
- First parameter: function to run
- Second parameter: dependency array
- Empty array
[]
means run once on mount [tasks]
means run whenever tasks change
Step 5: Adding Animations and Transitions
Enhancing User Experience
Add this prompt:
Add smooth animations to the task manager:
- Fade in animation when adding tasks
- Slide and fade out when deleting tasks
- Smooth transitions for completing tasks
- Add a subtle hover effect on task items
Animated TaskItem Component
import React, { useState } from 'react';
function TaskItem({ task, onToggle, onDelete }) {
const [isDeleting, setIsDeleting] = useState(false);
const handleDelete = () => {
setIsDeleting(true);
setTimeout(() => onDelete(task.id), 300);
};
return (
<div
className={`
flex items-center gap-3 p-4 bg-white rounded-lg shadow-sm
transform transition-all duration-300 hover:shadow-md
${isDeleting ? 'translate-x-full opacity-0' : 'translate-x-0 opacity-100'}
${task.completed ? 'opacity-75' : ''}
`}
>
<input
type="checkbox"
checked={task.completed}
onChange={() => onToggle(task.id)}
className="w-5 h-5 text-blue-500 rounded focus:ring-2 focus:ring-blue-300"
/>
<span
className={`
flex-1 text-gray-800 transition-all duration-200
${task.completed ? 'line-through text-gray-500' : ''}
`}
>
{task.text}
</span>
<button
onClick={handleDelete}
className="text-red-500 hover:text-red-700 transition-colors"
>
Delete
</button>
</div>
);
}
Step 6: Adding Edit Functionality
Making Tasks Editable
Add this feature with the prompt:
Add the ability to edit tasks:
- Double-click a task to edit it
- Show an input field in place of the task text
- Save on Enter or blur
- Cancel on Escape
- Maintain all existing functionality
Enhanced TaskItem with Edit Mode
function TaskItem({ task, onToggle, onDelete, onEdit }) {
const [isEditing, setIsEditing] = useState(false);
const [editText, setEditText] = useState(task.text);
const handleEdit = () => {
if (editText.trim() && editText !== task.text) {
onEdit(task.id, editText.trim());
}
setIsEditing(false);
};
const handleKeyDown = (e) => {
if (e.key === 'Enter') {
handleEdit();
} else if (e.key === 'Escape') {
setEditText(task.text);
setIsEditing(false);
}
};
return (
<div className="task-item">
{/* Checkbox */}
{isEditing ? (
<input
type="text"
value={editText}
onChange={(e) => setEditText(e.target.value)}
onBlur={handleEdit}
onKeyDown={handleKeyDown}
className="flex-1 px-2 py-1 border rounded"
autoFocus
/>
) : (
<span
onDoubleClick={() => setIsEditing(true)}
className="flex-1 cursor-pointer"
>
{task.text}
</span>
)}
{/* Delete button */}
</div>
);
}
Step 7: Adding Statistics and Progress
Creating a Statistics Component
Add this prompt:
Add a statistics section showing:
- Total tasks
- Completed tasks
- Completion percentage with a progress bar
- Productivity streak (consecutive days with completed tasks)
Style it as a card above the task list
Statistics Component
function Statistics({ tasks }) {
const totalTasks = tasks.length;
const completedTasks = tasks.filter(task => task.completed).length;
const percentage = totalTasks > 0
? Math.round((completedTasks / totalTasks) * 100)
: 0;
return (
<div className="bg-white rounded-lg shadow-sm p-6 mb-6">
<h2 className="text-xl font-semibold mb-4">Your Progress</h2>
<div className="grid grid-cols-3 gap-4 mb-4">
<div className="text-center">
<div className="text-3xl font-bold text-blue-500">{totalTasks}</div>
<div className="text-sm text-gray-600">Total Tasks</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold text-green-500">{completedTasks}</div>
<div className="text-sm text-gray-600">Completed</div>
</div>
<div className="text-center">
<div className="text-3xl font-bold text-purple-500">{percentage}%</div>
<div className="text-sm text-gray-600">Progress</div>
</div>
</div>
<div className="w-full bg-gray-200 rounded-full h-3">
<div
className="bg-gradient-to-r from-blue-500 to-green-500 h-3 rounded-full transition-all duration-500"
style={{ width: `${percentage}%` }}
/>
</div>
</div>
);
}
Step 8: Optimizing Performance
React Performance Best Practices
- Use React.memo for expensive components:
const TaskItem = React.memo(({ task, onToggle, onDelete }) => {
// Component code
});
- Use useCallback for function props:
const toggleTask = useCallback((id) => {
setTasks(prevTasks =>
prevTasks.map(task =>
task.id === id ? { ...task, completed: !task.completed } : task
)
);
}, []);
- Use useMemo for expensive calculations:
const statistics = useMemo(() => {
return {
total: tasks.length,
completed: tasks.filter(t => t.completed).length,
active: tasks.filter(t => !t.completed).length
};
}, [tasks]);
Step 9: Adding Keyboard Shortcuts
Implementing Keyboard Navigation
Add this enhancement:
Add keyboard shortcuts:
- Ctrl/Cmd + Enter to add a task from anywhere
- Delete key to delete selected task
- Space to toggle selected task
- Arrow keys to navigate tasks
Show shortcuts in a help modal (? key)
Step 10: Deploying Your React App
Deployment Process
-
Test your application thoroughly:
- Add several tasks
- Complete and delete tasks
- Test all filters
- Verify persistence works
-
Deploy to Netlify:
- Click the "Deploy" button
- Sign in to Netlify
- Choose a site name
- Click "Deploy"
-
Your app is now live!
- Share the URL with others
- Access it from any device
- Updates deploy automatically
Common React Patterns in Bolt.new
1. Custom Hooks
Create reusable logic:
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const savedValue = localStorage.getItem(key);
return savedValue ? JSON.parse(savedValue) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
2. Context API for Global State
For larger apps:
const TaskContext = React.createContext();
function TaskProvider({ children }) {
const [tasks, setTasks] = useState([]);
return (
<TaskContext.Provider value={{ tasks, setTasks }}>
{children}
</TaskContext.Provider>
);
}
3. Error Boundaries
Handle errors gracefully:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Troubleshooting Common React Issues
1. State Not Updating
Problem: UI doesn't reflect state changes Solution: Ensure you're creating new objects/arrays:
// Wrong
state.push(newItem);
setState(state);
// Correct
setState([...state, newItem]);
2. Infinite Renders
Problem: Component renders continuously Solution: Check useEffect dependencies:
// Wrong - creates new object every render
useEffect(() => {
// ...
}, [{ id: 1 }]);
// Correct
useEffect(() => {
// ...
}, [id]);
3. Performance Issues
Problem: App feels sluggish Solutions:
- Use React.memo for pure components
- Implement virtualization for long lists
- Use production build for deployment
Best Practices for React in Bolt.new
- Start Simple: Build core functionality first
- Component Organization: Keep components small and focused
- State Management: Lift state up only when necessary
- Naming Conventions: Use descriptive names for components and props
- Accessibility: Include proper ARIA labels and keyboard support
Next Steps and Challenges
Challenge 1: Add Categories
Enhance the app with task categories:
- Add a category dropdown to the form
- Filter tasks by category
- Show category badges on tasks
Challenge 2: Due Dates
Add time management:
- Add date picker for due dates
- Sort tasks by due date
- Highlight overdue tasks
Challenge 3: Drag and Drop
Implement task reordering:
- Make tasks draggable
- Update order in state
- Persist new order
Additional Resources
- React Documentation: react.dev
- Bolt.new React Examples: Browse the showcase
- React Patterns: Modern React patterns and best practices
- Component Libraries: Explore UI libraries like Material-UI or Ant Design
Summary
You've successfully built a feature-rich React application with Bolt.new! You've learned:
- Creating React apps without setup
- Component-based architecture
- State management with hooks
- Styling with Tailwind CSS
- Adding persistence and animations
- Deploying to production
The combination of React and Bolt.new provides a powerful development experience that lets you focus on building great user interfaces without worrying about configuration.
Final Project Enhancement
Try adding these advanced features:
- User authentication
- Cloud sync with a backend
- Task sharing and collaboration
- Data export functionality
- Theme customization
Remember, Bolt.new's AI assistance makes even complex features achievable. Experiment, iterate, and build something amazing!