One of the most common questions beginners ask is: "Why should I learn React when I can already build websites with HTML, CSS, and JavaScript?" It's a great question! In this lesson, we'll explore the key differences between React and vanilla JavaScript, and help you understand when each approach makes the most sense.
What is Vanilla JavaScript?
"Vanilla JavaScript" simply means plain JavaScript without any libraries or frameworks. It's the native JavaScript that runs in your browser, using the DOM (Document Object Model) API to interact with web pages.
When you write code like document.getElementById() or element.addEventListener(), you're using vanilla JavaScript. It's powerful, it's fast, and it's the foundation of everything that runs on the web.
A Simple Example: Counter App
Let's build the same simple counter application in both vanilla JavaScript and React to see the differences firsthand.
Vanilla JavaScript Approach
<!DOCTYPE html>
<html>
<head>
<title>Vanilla JS Counter</title>
<style>
.container {
padding: 2rem;
text-align: center;
}
.count {
font-size: 3rem;
font-weight: bold;
color: #6366f1;
margin: 1rem 0;
}
button {
padding: 0.75rem 1.5rem;
margin: 0.5rem;
font-size: 1rem;
border: none;
border-radius: 0.5rem;
cursor: pointer;
background-color: #6366f1;
color: white;
}
button:hover {
background-color: #4f46e5;
}
</style>
</head>
<body>
<div class="container">
<h1>Counter App</h1>
<div class="count" id="count">0</div>
<button id="decrement">-</button>
<button id="reset">Reset</button>
<button id="increment">+</button>
</div>
<script>
let count = 0;
const countElement = document.getElementById('count');
const decrementBtn = document.getElementById('decrement');
const resetBtn = document.getElementById('reset');
const incrementBtn = document.getElementById('increment');
function updateDisplay() {
countElement.textContent = count;
}
decrementBtn.addEventListener('click', () => {
count--;
updateDisplay();
});
resetBtn.addEventListener('click', () => {
count = 0;
updateDisplay();
});
incrementBtn.addEventListener('click', () => {
count++;
updateDisplay();
});
</script>
</body>
</html>React Approach
function Counter() {
const [count, setCount] = useState(0);
return (
<div className="container">
<h1>Counter App</h1>
<div className="count">{count}</div>
<button onClick={() => setCount(count - 1)}>-</button>
<button onClick={() => setCount(0)}>Reset</button>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}Notice how the React version is more concise and declarative. You describe what the UI should look like based on the current state, rather than how to update the DOM step by step.
💡 Tip: Edit the code above and click "Run" to see your changes
Key Differences
Let's break down the fundamental differences between vanilla JavaScript and React:
1. DOM Manipulation
Vanilla JavaScript: You directly manipulate the DOM using methods like getElementById(), createElement(), appendChild(), and innerHTML. This is called imperative programming - you tell the browser exactly what to do, step by step.
// Imperative: Tell the browser HOW to do it
const button = document.createElement('button');
button.textContent = 'Click me';
button.classList.add('btn');
button.addEventListener('click', handleClick);
document.body.appendChild(button);
// Update the button text
button.textContent = 'Clicked!';React: You describe what the UI should look like for any given state, and React handles the DOM updates for you. This is called declarative programming - you describe what you want, not how to do it.
// Declarative: Describe WHAT you want
function Button() {
const [clicked, setClicked] = useState(false);
return (
<button
className="btn"
onClick={() => setClicked(true)}
>
{clicked ? 'Clicked!' : 'Click me'}
</button>
);
}2. State Management
Vanilla JavaScript: You manage state manually using variables and need to manually update the UI whenever state changes.
let user = { name: 'John', age: 25 };
function updateUser(newName) {
user.name = newName;
// Manually update ALL places where user.name is displayed
document.getElementById('userName').textContent = user.name;
document.getElementById('greeting').textContent = 'Hello, ' + user.name;
document.getElementById('profile').textContent = user.name + "'s Profile";
// Easy to miss updates or create bugs!
}React: State is managed with hooks like useState, and the UI automatically updates when state changes.
function UserProfile() {
const [user, setUser] = useState({ name: 'John', age: 25 });
// React automatically re-renders when user changes
return (
<div>
<div id="userName">{user.name}</div>
<div id="greeting">Hello, {user.name}</div>
<div id="profile">{user.name}'s Profile</div>
<button onClick={() => setUser({ ...user, name: 'Jane' })}>
Change Name
</button>
</div>
);
}3. Code Organization
Vanilla JavaScript: As applications grow, code can become scattered across HTML, CSS, and JavaScript files, making it harder to maintain.
React: Everything related to a component (logic, structure, and sometimes even styles) lives together, making code more modular and maintainable.
4. Reusability
Vanilla JavaScript: Reusing code often requires copying and pasting or writing complex functions that manipulate the DOM.
React: Components are inherently reusable. Write once, use anywhere with different props.
function Button({ text, color, onClick }) {
return (
<button
style={{ backgroundColor: color }}
onClick={onClick}
>
{text}
</button>
);
}
// Use the same component multiple times
<Button text="Save" color="green" onClick={handleSave} />
<Button text="Cancel" color="red" onClick={handleCancel} />
<Button text="Submit" color="blue" onClick={handleSubmit} />A More Complex Example: Todo List
Let's see how the differences become even more apparent in a slightly more complex application - a todo list.
Vanilla JavaScript Todo List
let todos = [];
let nextId = 1;
const input = document.getElementById('todoInput');
const addBtn = document.getElementById('addBtn');
const todoList = document.getElementById('todoList');
function renderTodos() {
// Clear the entire list
todoList.innerHTML = '';
// Re-render everything from scratch
todos.forEach(todo => {
const li = document.createElement('li');
li.className = todo.completed ? 'completed' : '';
const checkbox = document.createElement('input');
checkbox.type = 'checkbox';
checkbox.checked = todo.completed;
checkbox.addEventListener('click', () => toggleTodo(todo.id));
const span = document.createElement('span');
span.textContent = todo.text;
const deleteBtn = document.createElement('button');
deleteBtn.textContent = 'Delete';
deleteBtn.addEventListener('click', () => deleteTodo(todo.id));
li.appendChild(checkbox);
li.appendChild(span);
li.appendChild(deleteBtn);
todoList.appendChild(li);
});
}
function addTodo() {
const text = input.value.trim();
if (text) {
todos.push({ id: nextId++, text, completed: false });
input.value = '';
renderTodos(); // Re-render entire list
}
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
renderTodos(); // Re-render entire list
}
}
function deleteTodo(id) {
todos = todos.filter(t => t.id !== id);
renderTodos(); // Re-render entire list
}
addBtn.addEventListener('click', addTodo);
input.addEventListener('keypress', (e) => {
if (e.key === 'Enter') addTodo();
});React Todo List
function TodoList() {
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');
const [nextId, setNextId] = useState(1);
const addTodo = () => {
if (inputValue.trim()) {
setTodos([...todos, {
id: nextId,
text: inputValue,
completed: false
}]);
setInputValue('');
setNextId(nextId + 1);
}
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
));
};
const deleteTodo = (id) => {
setTodos(todos.filter(todo => todo.id !== id));
};
return (
<div>
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && addTodo()}
/>
<button onClick={addTodo}>Add</button>
<ul>
{todos.map(todo => (
<li key={todo.id} className={todo.completed ? 'completed' : ''}>
<input
type="checkbox"
checked={todo.completed}
onChange={() => toggleTodo(todo.id)}
/>
<span>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
</div>
);
}Try the interactive React version below. Notice how clean and intuitive the code is:
💡 Tip: Edit the code above and click "Run" to see your changes
When to Use Vanilla JavaScript
Vanilla JavaScript is perfect for:
- Simple, static websites - Like landing pages or blogs with minimal interactivity
- Small interactive features - Adding a simple dropdown menu, image slider, or form validation
- Learning web fundamentals - Understanding how the DOM works before diving into frameworks
- Performance-critical pages - When you need the absolute smallest file size and fastest load time
- Legacy projects - Maintaining existing codebases that don't use frameworks
- Simple browser extensions - Chrome/Firefox extensions with basic functionality
Rule of thumb: If your entire JavaScript logic fits comfortably in one file (under 200 lines) and you're not planning to scale, vanilla JavaScript might be all you need!
When to Use React
React shines when building:
- Single Page Applications (SPAs) - Apps where content changes dynamically without page reloads (Gmail, Twitter, Facebook)
- Complex user interfaces - Dashboards, admin panels, data visualization tools
- Apps with lots of state - Applications where data changes frequently and UI needs to stay in sync
- Component-heavy projects - When you'll reuse UI elements across many pages
- Team projects - React's component model makes it easier for teams to work together
- Apps that will scale - When you expect to add features over time
- Real-time applications - Chat apps, collaborative tools, live dashboards
- E-commerce platforms - Shopping carts, product filters, dynamic pricing
Performance Considerations
Let's talk about performance - a common concern when choosing between vanilla JavaScript and React.
Initial Load Time
Vanilla JavaScript wins here. With no framework to download, vanilla JavaScript has the smallest initial bundle size. A simple page might be just a few kilobytes.
React adds about 130KB (minified and gzipped) to your bundle. For a simple counter or todo list, this overhead might not be worth it.
Runtime Performance
React often wins for complex UIs. Thanks to the Virtual DOM, React is extremely efficient at updating the actual DOM. It calculates the minimum changes needed and batches updates together.
With vanilla JavaScript, you might accidentally re-render more than necessary or make inefficient DOM updates, especially as complexity grows.
Developer Productivity
This is where React really shines. While vanilla JavaScript might be faster to write for a simple feature, React typically results in:
- Fewer bugs (declarative code is easier to reason about)
- Faster development for complex features
- Easier maintenance and refactoring
- Better code organization
- More reusable components
Real-World Decision Scenarios
Let's look at some real-world scenarios to help you decide:
Scenario 1: Personal Blog
Project: A personal blog with articles, an about page, and a contact form.
Best Choice: Vanilla JavaScript (or even just HTML/CSS)
Why: Minimal interactivity needed. The extra complexity and bundle size of React aren't justified.
Scenario 2: Task Management App
Project: A productivity app where users can create projects, add tasks, set priorities, filter by status, and track progress.
Best Choice: React
Why: Lots of interactive features, state management needs, and reusable components (task items, project cards, filters).
Scenario 3: Restaurant Website
Project: A restaurant website with menu, hours, location, and a reservation form.
Best Choice: Vanilla JavaScript
Why: Mostly static content. Maybe a simple image carousel or menu filter - easily done with vanilla JS.
Scenario 4: Social Media Dashboard
Project: An analytics dashboard showing social media metrics, graphs, real-time updates, and user interactions.
Best Choice: React
Why: Complex state management, real-time data updates, interactive charts, and many reusable components.
Scenario 5: Adding a Modal to Existing Site
Project: You need to add a popup modal to an existing website.
Best Choice: Vanilla JavaScript
Why: Adding React for one feature in an existing vanilla site is overkill. A simple vanilla implementation is cleaner.
Learning Curve Comparison
Let's be honest about the learning investment required:
Vanilla JavaScript
- Pros: If you know JavaScript, you already know vanilla JavaScript. The DOM API is straightforward.
- Cons: You need to learn best practices for organizing code, managing state, and avoiding common pitfalls. These lessons often come from making mistakes.
- Time to productivity: Immediate for simple tasks, but can become messy for complex apps.
React
- Pros: Once you understand the core concepts (components, props, state, hooks), you can build complex applications with confidence.
- Cons: Initial learning curve. You need to understand JSX, component lifecycle, hooks, and the React way of thinking.
- Time to productivity: 1-2 weeks to grasp basics, 2-3 months to feel comfortable, ongoing learning for advanced patterns.
Good news: Once you learn React, you've learned transferable concepts that apply to other modern frameworks like Vue, Angular, and even mobile development with React Native!
Ecosystem and Community
Another important factor to consider is the ecosystem around each approach:
Vanilla JavaScript
- Unlimited flexibility - you can use any library or approach
- No opinionated structure - freedom can be overwhelming
- Smaller community for specific patterns
- Need to reinvent common solutions
React
- Massive ecosystem of ready-to-use libraries
- React Router for navigation, Redux/Zustand for state, React Query for data fetching
- Component libraries like Material-UI, Ant Design, Chakra UI
- Huge community - easy to find solutions to common problems
- Regular updates and improvements from Meta
- Tons of learning resources, tutorials, and courses
Can They Work Together?
Absolutely! You don't have to choose one or the other for your entire project:
- Progressive enhancement: Start with vanilla JavaScript, then introduce React for specific interactive features
- Micro-frontends: Use React for complex parts of your site while keeping simple pages in vanilla JavaScript
- Gradual migration: Slowly migrate a vanilla JavaScript app to React, one component at a time
Many large websites use this hybrid approach, using frameworks like React only where they add real value.
Making Your Decision
Here's a simple decision tree to help you choose:
- Is this a simple, mostly static site with minimal interactivity?
→ Use vanilla JavaScript - Will the project scale and require many interactive components?
→ Use React - Do you need to share state between many components?
→ Use React - Is this a single feature in an existing vanilla site?
→ Stick with vanilla JavaScript - Are you building a team project that will be maintained long-term?
→ Use React - Is initial load performance absolutely critical?
→ Consider vanilla JavaScript - Not sure yet?
→ Learn both! Start simple with vanilla, graduate to React when needed
Key Takeaways
- Vanilla JavaScript is great for simple, static sites and small interactive features
- React excels at complex, interactive applications with lots of state management
- Vanilla JavaScript has faster initial load, React has better runtime performance for complex UIs
- React has a steeper learning curve but pays off for larger projects
- React's declarative approach makes code easier to understand and maintain
- The React ecosystem provides solutions for common problems
- You don't have to choose just one - they can work together
- Your project requirements should drive the decision, not trends
- Learning vanilla JavaScript first helps you appreciate what React does for you
What's Next?
Now that you understand when and why to use React, it's time to get your hands dirty! In the next lesson, we'll set up your development environment and create your first React application using Vite.
You'll learn how to install Node.js, set up a modern React project, and understand the file structure of a React app. Get ready to write some code! 🚀