Migration Overview
Transitioning from vanilla JavaScript to React isn't about abandoning everything you know. It's about applying your existing knowledge in a new, more structured way that makes building complex UIs easier and more maintainable.
๐ฏ What You'll Gain
๐ฆ Component Reusability
Build once, use everywhere. Components eliminate code duplication.
๐ Declarative UI
Describe what the UI should look like, not how to manipulate it.
๐๏ธ State Management
Predictable state updates and automatic UI synchronization.
๐ง Developer Tools
Amazing debugging tools and development experience.
Step-by-Step Migration Process
๐ Phase 1: Learn the Fundamentals
// DOM Manipulation
const button = document.getElementById('myButton');
button.addEventListener('click', handleClick);
// Creating Elements
const div = document.createElement('div');
div.textContent = 'Hello World';
document.body.appendChild(div);
// Updating Content
function updateCounter(count) {
document.getElementById('counter').textContent = count;
}
// Event Handling
function handleClick(event) {
console.log('Button clicked!');
}
// Component with State
function Counter() {
const [count, setCount] = useState(0);
const handleClick = () => {
console.log('Button clicked!');
setCount(count + 1);
};
return (
<div>
<div>Hello World</div>
<div id="counter">{count}</div>
<button id="myButton" onClick={handleClick}>
Click me
</button>
</div>
);
}
๐ ๏ธ Phase 2: Identify Reusable Patterns
Look at your existing code and identify repeated patterns that could become components:
// Vanilla JS: Repeated modal code
function createModal(title, content) {
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-content">
<h2>${title}</h2>
<p>${content}</p>
<button class="close-btn">Close</button>
</div>
`;
document.body.appendChild(modal);
}
// React: Reusable Modal Component
function Modal({ title, content, isOpen, onClose }) {
if (!isOpen) return null;
return (
<div className="modal">
<div className="modal-content">
<h2>{title}</h2>
<p>{content}</p>
<button className="close-btn" onClick={onClose}>
Close
</button>
</div>
</div>
);
}
// Usage is clean and declarative
function App() {
const [showModal, setShowModal] = useState(false);
return (
<div>
<button onClick={() => setShowModal(true)}>
Open Modal
</button>
<Modal
title="Welcome"
content="This is a reusable modal!"
isOpen={showModal}
onClose={() => setShowModal(false)}
/>
</div>
);
}
๐ Phase 3: Convert Data Handling
let todos = [];
function addTodo(text) {
todos.push({ id: Date.now(), text, done: false });
renderTodos();
}
function toggleTodo(id) {
const todo = todos.find(t => t.id === id);
if (todo) {
todo.done = !todo.done;
renderTodos();
}
}
function renderTodos() {
const container = document.getElementById('todos');
container.innerHTML = '';
todos.forEach(todo => {
const div = document.createElement('div');
div.innerHTML = `
<input
type="checkbox"
${todo.done ? 'checked' : ''}
onchange="toggleTodo(${todo.id})"
>
<span>${todo.text}</span>
`;
container.appendChild(div);
});
}
function TodoApp() {
const [todos, setTodos] = useState([]);
const addTodo = (text) => {
setTodos([...todos, {
id: Date.now(),
text,
done: false
}]);
};
const toggleTodo = (id) => {
setTodos(todos.map(todo =>
todo.id === id
? { ...todo, done: !todo.done }
: todo
));
};
return (
<div>
<TodoInput onAdd={addTodo} />
<div id="todos">
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={toggleTodo}
/>
))}
</div>
</div>
);
}
Common Migration Patterns
๐ Event Handling
// Vanilla JS
document.getElementById('btn').addEventListener('click', (e) => {
e.preventDefault();
console.log('Clicked!');
});
// React
<button onClick={(e) => {
e.preventDefault();
console.log('Clicked!');
}}>
Click me
</button>
๐ Form Handling
// Vanilla JS
const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
e.preventDefault();
const formData = new FormData(form);
const name = formData.get('name');
// Process form...
});
// React
function ContactForm() {
const [name, setName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
// Process form...
};
return (
<form onSubmit={handleSubmit}>
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
</form>
);
}
๐ API Calls
// Vanilla JS
async function loadUsers() {
const response = await fetch('/api/users');
const users = await response.json();
const container = document.getElementById('users');
container.innerHTML = users.map(user =>
`<div>${user.name}</div>`
).join('');
}
// React
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('/api/users')
.then(res => res.json())
.then(setUsers);
}, []);
return (
<div>
{users.map(user => (
<div key={user.id}>{user.name}</div>
))}
</div>
);
}
๐จ Dynamic Styling
// Vanilla JS
const element = document.getElementById('status');
if (isActive) {
element.classList.add('active');
element.style.color = 'green';
} else {
element.classList.remove('active');
element.style.color = 'red';
}
// React
<div
className={`status ${isActive ? 'active' : ''}`}
style={{ color: isActive ? 'green' : 'red' }}
>
Status
</div>
Migration Checklist
โ Pre-Migration Planning
๐ Audit Your Code
- โ Identify repeated UI patterns
- โ List all event handlers
- โ Document data flow
- โ Note third-party dependencies
- โ Map out component hierarchy
โ๏ธ Setup Environment
- โ Install Node.js and npm
- โ Choose build tool (CRA or Vite)
- โ Set up development environment
- โ Install React DevTools
- โ Configure code editor
๐๏ธ Migration Steps
๐ฆ Phase 1: Component Creation
- โ Start with simplest components
- โ Convert reusable UI pieces
- โ Replace innerHTML with JSX
- โ Update class to className
- โ Convert event listeners
๐๏ธ Phase 2: State Management
- โ Identify state variables
- โ Convert to useState hooks
- โ Update state setter functions
- โ Handle side effects with useEffect
- โ Lift state up when needed
๐ Phase 3: Data Flow
- โ Convert API calls to useEffect
- โ Implement proper loading states
- โ Add error handling
- โ Update form handling
- โ Test component interactions
โจ Phase 4: Polish & Optimize
- โ Add proper key props
- โ Implement error boundaries
- โ Optimize re-renders
- โ Add accessibility features
- โ Write tests
Migration Best Practices
๐ฏ Start Small
- Begin with isolated components
- Don't migrate everything at once
- Test each component thoroughly
- Gradually increase complexity
๐ Incremental Approach
- You can mix React with vanilla JS
- Migrate page by page
- Keep existing APIs working
- Plan for gradual rollout
๐ Learn as You Go
- Don't try to learn everything first
- Focus on immediate needs
- Read documentation actively
- Join React communities
๐งช Test Everything
- Set up testing from the start
- Test user interactions
- Verify edge cases
- Monitor performance
Common Pitfalls to Avoid
โ ๏ธ Watch Out For
๐ Direct DOM Manipulation
Avoid using document.getElementById() or direct DOM manipulation in React. Let React manage the DOM.
function BadComponent() {
useEffect(() => {
document.getElementById('myDiv').style.color = 'red';
});
return <div id="myDiv">Text</div>;
}
function GoodComponent() {
const [color, setColor] = useState('red');
return (
<div style={{ color }}>
Text
</div>
);
}
๐ State Mutations
Never mutate state directly. Always create new objects/arrays.
const [items, setItems] = useState([]);
// Wrong - mutates existing array
const addItem = (item) => {
items.push(item);
setItems(items);
};
const [items, setItems] = useState([]);
// Correct - creates new array
const addItem = (item) => {
setItems([...items, item]);
};
Your Migration Journey
Congratulations! You now have a clear roadmap for transitioning from vanilla JavaScript to React. Remember, this is a journey, not a race. Take your time to understand each concept thoroughly.
๐ Continue Your Journey
- Learning Path - Structured approach to mastering React
- Resources - External learning materials and documentation
- Home - Review all concepts from the beginning