Building Full-Stack React Apps with Bolt.new

Create complete React applications with backend integration using Bolt.new

60 min
Intermediate
75% completion rate
50% popularity
bolt-new
react
full-stack
deployment
web-apps

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

  1. Functional Components: Modern React uses functions instead of classes
  2. Props: onAddTask is passed from parent to child
  3. useState Hook: Manages local component state
  4. Event Handling: Form submission and input changes
  5. 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

  1. Use React.memo for expensive components:
const TaskItem = React.memo(({ task, onToggle, onDelete }) => {
  // Component code
});
  1. Use useCallback for function props:
const toggleTask = useCallback((id) => {
  setTasks(prevTasks => 
    prevTasks.map(task =>
      task.id === id ? { ...task, completed: !task.completed } : task
    )
  );
}, []);
  1. 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

  1. Test your application thoroughly:

    • Add several tasks
    • Complete and delete tasks
    • Test all filters
    • Verify persistence works
  2. Deploy to Netlify:

    • Click the "Deploy" button
    • Sign in to Netlify
    • Choose a site name
    • Click "Deploy"
  3. 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

  1. Start Simple: Build core functionality first
  2. Component Organization: Keep components small and focused
  3. State Management: Lift state up only when necessary
  4. Naming Conventions: Use descriptive names for components and props
  5. 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:

  1. User authentication
  2. Cloud sync with a backend
  3. Task sharing and collaboration
  4. Data export functionality
  5. Theme customization

Remember, Bolt.new's AI assistance makes even complex features achievable. Experiment, iterate, and build something amazing!

Your Progress

Not started