Skip to content

Commit 14df6f7

Browse files
authored
Merge pull request #379 from codomposer/feat/custom_hook
add new coding exercise for custom hook
2 parents bcdb32b + f6f2727 commit 14df6f7

File tree

4 files changed

+502
-0
lines changed

4 files changed

+502
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import React, { useState, useEffect } from 'react';
2+
3+
/**
4+
* CODING EXERCISE 4: Custom Hooks and Code Reusability
5+
*
6+
* PROBLEM:
7+
* You have two components that fetch data from different APIs.
8+
* Both components have similar logic for loading, error handling, and data fetching.
9+
*
10+
* Question: What's wrong with this code?
11+
*
12+
* Options:
13+
* A) Nothing is wrong, this is the correct way
14+
* B) Code duplication - should extract into a custom hook
15+
* C) Missing cleanup in useEffect
16+
* D) Should use fetch instead of hardcoded data
17+
*
18+
* BONUS: How would you create a reusable custom hook for this pattern?
19+
*/
20+
21+
// Component 1: Fetches user data
22+
function UserProfile() {
23+
const [data, setData] = useState(null);
24+
const [loading, setLoading] = useState(true);
25+
const [error, setError] = useState(null);
26+
27+
useEffect(() => {
28+
setLoading(true);
29+
// Simulating API call
30+
setTimeout(() => {
31+
try {
32+
setData({ name: 'John Doe', email: '[email protected]' });
33+
setLoading(false);
34+
} catch (err) {
35+
setError(err.message);
36+
setLoading(false);
37+
}
38+
}, 1000);
39+
}, []);
40+
41+
if (loading) return <div>Loading user...</div>;
42+
if (error) return <div>Error: {error}</div>;
43+
return (
44+
<div style={{ padding: '10px', backgroundColor: '#e3f2fd', borderRadius: '5px', marginBottom: '10px' }}>
45+
<h4>User Profile</h4>
46+
<p>Name: {data?.name}</p>
47+
<p>Email: {data?.email}</p>
48+
</div>
49+
);
50+
}
51+
52+
// Component 2: Fetches posts data (DUPLICATE LOGIC!)
53+
function PostsList() {
54+
const [data, setData] = useState(null);
55+
const [loading, setLoading] = useState(true);
56+
const [error, setError] = useState(null);
57+
58+
useEffect(() => {
59+
setLoading(true);
60+
// Simulating API call
61+
setTimeout(() => {
62+
try {
63+
setData([
64+
{ id: 1, title: 'First Post' },
65+
{ id: 2, title: 'Second Post' }
66+
]);
67+
setLoading(false);
68+
} catch (err) {
69+
setError(err.message);
70+
setLoading(false);
71+
}
72+
}, 1000);
73+
}, []);
74+
75+
if (loading) return <div>Loading posts...</div>;
76+
if (error) return <div>Error: {error}</div>;
77+
return (
78+
<div style={{ padding: '10px', backgroundColor: '#fff3e6', borderRadius: '5px' }}>
79+
<h4>Posts</h4>
80+
{data?.map(post => (
81+
<p key={post.id}>{post.title}</p>
82+
))}
83+
</div>
84+
);
85+
}
86+
87+
function Problem() {
88+
return (
89+
<div style={{ padding: '20px', fontFamily: 'Arial' }}>
90+
<h2>Exercise 4: Custom Hooks Problem</h2>
91+
92+
<div style={{ marginBottom: '20px' }}>
93+
<UserProfile />
94+
<PostsList />
95+
</div>
96+
97+
<div style={{
98+
marginTop: '20px',
99+
padding: '10px',
100+
backgroundColor: '#fff3cd',
101+
border: '1px solid #ffc107',
102+
borderRadius: '5px'
103+
}}>
104+
<p><strong>⚠️ Question:</strong> What's the problem with this code?</p>
105+
<p>Think about:</p>
106+
<ul>
107+
<li>Is there code duplication?</li>
108+
<li>How would you make this reusable?</li>
109+
<li>What would a custom hook look like?</li>
110+
<li>What are the benefits of extracting this logic?</li>
111+
</ul>
112+
<p style={{ fontSize: '12px', color: '#856404' }}>
113+
<strong>Hint:</strong> Look at the similar patterns in both components
114+
</p>
115+
</div>
116+
117+
<div style={{
118+
marginTop: '15px',
119+
padding: '10px',
120+
backgroundColor: '#ffe6e6',
121+
borderRadius: '5px'
122+
}}>
123+
<h4>❌ Code Smell Detected</h4>
124+
<ul style={{ fontSize: '14px' }}>
125+
<li>Both components have identical state management (data, loading, error)</li>
126+
<li>Both have the same useEffect pattern</li>
127+
<li>Both have the same conditional rendering logic</li>
128+
<li>If we need to add a feature (e.g., retry), we'd have to update both!</li>
129+
</ul>
130+
</div>
131+
</div>
132+
);
133+
}
134+
135+
export default Problem;

0 commit comments

Comments
 (0)