
React Hooks revolutionized how we write React components. At SwedTech Academy, we teach you modern React practices from the start, focusing on functional components and hooks.
Hooks are functions that let you use state and other React features in functional components. Before hooks, you needed class components for state management. Now, functional components can do everything!
useState is the most fundamental hook. It lets you add state to functional components.
import React, { useState } from 'react';
function Counter() {
// Declare state variable
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
const [stateVariable, setStateVariable] = useState(initialValue);
function ToggleButton() {
const [isOn, setIsOn] = useState(false);
return (
<button onClick={() => setIsOn(!isOn)}>
{isOn ? 'ON' : 'OFF'}
</button>
);
}
function UserForm() {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [age, setAge] = useState(0);
return (
<form>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Name"
/>
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="number"
value={age}
onChange={(e) => setAge(e.target.value)}
placeholder="Age"
/>
</form>
);
}
function UserProfile() {
const [user, setUser] = useState({
name: '',
email: '',
age: 0
});
const updateUser = (field, value) => {
setUser(prevUser => ({
...prevUser,
[field]: value
}));
};
return (
<div>
<input
value={user.name}
onChange={(e) => updateUser('name', e.target.value)}
/>
<input
value={user.email}
onChange={(e) => updateUser('email', e.target.value)}
/>
</div>
);
}
useEffect lets you perform side effects in functional components. Side effects include:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
// Runs after every render
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<button onClick={() => setCount(count + 1)}>
Click me
</button>
);
}
Control when effects run using the dependency array:
// Runs after every render
useEffect(() => {
console.log('After every render');
});
// Runs only once (on mount)
useEffect(() => {
console.log('Only once');
}, []);
// Runs when dependencies change
useEffect(() => {
console.log(`Count changed: ${count}`);
}, [count]);
// Multiple dependencies
useEffect(() => {
console.log('Name or email changed');
}, [name, email]);
function UserList() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => {
setUsers(data);
setLoading(false);
})
.catch(error => {
console.error('Error:', error);
setLoading(false);
});
}, []); // Empty array = run once
if (loading) return <p>Loading...</p>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
// Cleanup function
return () => {
clearInterval(interval);
};
}, []);
return <div>Seconds: {seconds}</div>;
}
function WindowSize() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => {
setWidth(window.innerWidth);
};
window.addEventListener('resize', handleResize);
// Cleanup
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <div>Window width: {width}px</div>;
}
Real-world example: Search with debouncing
function SearchBar() {
const [searchTerm, setSearchTerm] = useState('');
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
if (!searchTerm) {
setResults([]);
return;
}
setLoading(true);
// Debounce: wait 500ms after user stops typing
const timer = setTimeout(() => {
fetch(`https://api.example.com/search?q=${searchTerm}`)
.then(res => res.json())
.then(data => {
setResults(data);
setLoading(false);
});
}, 500);
return () => clearTimeout(timer);
}, [searchTerm]);
return (
<div>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search..."
/>
{loading && <p>Loading...</p>}
<ul>
{results.map(result => (
<li key={result.id}>{result.title}</li>
))}
</ul>
</div>
);
}
// ❌ Wrong: Creates infinite loop
function BadExample() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(count + 1); // Updates count every render!
});
return <div>{count}</div>;
}
// ✅ Correct: Use dependency array
function GoodExample() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Count changed:', count);
}, [count]); // Only runs when count changes
return <div>{count}</div>;
}
// ❌ Memory leak!
useEffect(() => {
setInterval(() => {
console.log('Running...');
}, 1000);
}, []);
// ✅ Proper cleanup
useEffect(() => {
const interval = setInterval(() => {
console.log('Running...');
}, 1000);
return () => clearInterval(interval);
}, []);
// Custom hook for fetching data
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(err => {
setError(err);
setLoading(false);
});
}, [url]);
return { data, loading, error };
}
// Usage
function App() {
const { data, loading, error } = useFetch('https://api.example.com/data');
if (loading) return <p>Loading...</p>;
if (error) return <p>Error: {error.message}</p>;
return <div>{JSON.stringify(data)}</div>;
}
React is one of the most in-demand skills for frontend developers. In our Frontend Development and Full-Stack Development courses, you'll:
Ready to become a React expert? Enroll at SwedTech Academy and build your future!