Lesson: Controlled Components and Form Handling
- Creating forms in React
- Controlled vs uncontrolled components
- Handling form submissions
- Form validation
- Using the
useStatehook for form state
function SimpleForm() {
const [formData, setFormData] = useState({
username: '',
email: ''
});
const handleChange = (e) => {
const { name, value } = e.target;
setFormData(prev => ({
...prev,
[name]: value
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Form submitted:', formData);
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
/>
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
<button type="submit">Submit</button>
</form>
);
}Lesson: Understanding and Using Promises
- What are promises?
- Promise states (pending, fulfilled, rejected)
.then()and.catch()syntax- Async/await syntax
- Error handling with promises
// Basic promise example
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const success = Math.random() > 0.5;
if (success) {
resolve('Data fetched successfully!');
} else {
reject('Error fetching data');
}
}, 1000);
});
};
// Using in React component
function PromiseExample() {
const [data, setData] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
fetchData()
.then(result => setData(result))
.catch(err => setError(err));
}, []);
return (
<div>
{error && <p>Error: {error}</p>}
{data && <p>Data: {data}</p>}
{!error && !data && <p>Loading...</p>}
</div>
);
}What is an API? Technically speaking, API stands for Application Programming Interface. This sounds a little mysterious, so let's dig into it a little more. If you have a program, you may want it to communicate with another program that is written in a different technology, tech stack, etc. So, generally speaking, an API is the interface that allows one program/application to communicate with another. Think of it as a bridge. You can have two separate terrains, but an API is the bridge between the two.
Many times you will hear the term "RESTful API" or "REST API." A RESTful API, specifically, is an API that communicates among and between web services. These APIs follow a certain set of rules that make sure it is easy for people to implement them. By following a consistent set of conventions, learning different RESTful APIs will become quite easy and streamlined.
Lesson: REST API Fundamentals
- What is a REST API?
- HTTP methods (GET, POST, PUT, DELETE)
- Endpoints and resources
- Status codes
- Request/response format (typically JSON)
- API documentation
// Example REST API structure
const api = {
// Get all items
getItems: () => fetch('/api/items'),
// Get single item
getItem: (id) => fetch(`/api/items/${id}`),
// Create new item
createItem: (data) => fetch('/api/items', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
}),
// Update item
updateItem: (id, data) => fetch(`/api/items/${id}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
}),
// Delete item
deleteItem: (id) => fetch(`/api/items/${id}`, { method: 'DELETE' })
};Lesson: Fetching Data with useEffect
- Why useEffect for API calls?
- Dependency array
- Cleanup functions
- Loading states
- Error handling
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
// Cleanup function if needed
return () => {
// Cancel ongoing requests if component unmounts
};
}, []); // Empty dependency array means run once on mount
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}Lesson: Practical API Consumption with PokeAPI
- Understanding the PokeAPI endpoints
- Fetching data from a real-world API
- Displaying API data in components
- Pagination with offset/limit
function PokemonList() {
const [pokemon, setPokemon] = useState([]);
const [loading, setLoading] = useState(true);
const [offset, setOffset] = useState(0);
const limit = 10;
useEffect(() => {
const fetchPokemon = async () => {
setLoading(true);
try {
const response = await fetch(
`https://pokeapi.co/api/v2/pokemon?offset=${offset}&limit=${limit}`
);
const data = await response.json();
setPokemon(data.results);
} catch (error) {
console.error('Error fetching Pokemon:', error);
} finally {
setLoading(false);
}
};
fetchPokemon();
}, [offset]);
return (
<div>
<h1>Pokemon List</h1>
{loading ? (
<p>Loading...</p>
) : (
<ul>
{pokemon.map((p) => (
<li key={p.name}>{p.name}</li>
))}
</ul>
)}
<button onClick={() => setOffset(prev => Math.max(0, prev - limit))}>
Previous
</button>
<button onClick={() => setOffset(prev => prev + limit)}>
Next
</button>
</div>
);
}Lesson: Using Axios Instead of Fetch
- Why use Axios?
- Installing and setting up Axios
- GET, POST, PUT, DELETE with Axios
- Interceptors
- Error handling with Axios
import axios from 'axios';
function AxiosExample() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
useEffect(() => {
const fetchPosts = async () => {
setLoading(true);
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts');
setPosts(response.data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchPosts();
}, []);
const addPost = async (title, body) => {
try {
const response = await axios.post('https://jsonplaceholder.typicode.com/posts', {
title,
body,
userId: 1
});
setPosts(prev => [response.data, ...prev]);
} catch (err) {
setError(err.message);
}
};
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return (
<div>
<button onClick={() => addPost('New Post', 'This is the body')}>
Add Post
</button>
<ul>
{posts.slice(0, 5).map(post => (
<li key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</li>
))}
</ul>
</div>
);
}Lesson: Advanced API Consumption Techniques
- Custom hooks for API calls
- Handling pagination
- Debouncing search requests
- Caching responses
- Error boundaries
- Loading states and skeletons
// Custom hook for API calls
function useApi(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get(url);
setData(response.data);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
function PokemonDetail({ name }) {
const { data: pokemon, loading, error } = useApi(
`https://pokeapi.co/api/v2/pokemon/${name}`
);
if (loading) return <div>Loading {name}...</div>;
if (error) return <div>Error loading {name}</div>;
return (
<div>
<h2>{pokemon.name}</h2>
<img
src={pokemon.sprites.front_default}
alt={pokemon.name}
/>
<h3>Abilities:</h3>
<ul>
{pokemon.abilities.map((ability) => (
<li key={ability.ability.name}>{ability.ability.name}</li>
))}
</ul>
</div>
);
}- React Documentation: https://reactjs.org/docs/forms.html
- PokeAPI Documentation: https://pokeapi.co/
- Axios Documentation: https://axios-http.com/docs/intro
- MDN Fetch API: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
- JavaScript Promises: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
Would you like me to expand on any of these lessons or provide additional examples for specific scenarios?