Skip to content

Commit 03ba28d

Browse files
authored
Merge pull request #372 from xingarr/added_coding_exercise_challenge
feat: added some coding exercise challenges
2 parents d24fcf8 + 6a178c8 commit 03ba28d

File tree

1 file changed

+329
-0
lines changed

1 file changed

+329
-0
lines changed

coding-exercise/README.md

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,332 @@ If you try to use **{ref.current}** in the render method, the number won’t be
228228
---
229229
230230
**[⬆ Back to Top](#table-of-contents)**
231+
232+
#### 6. What is the output in the console after mounting and unmounting the component?
233+
234+
```javascript
235+
import { useEffect, useState } from 'react';
236+
237+
export default function Timer() {
238+
const [count, setCount] = useState(0);
239+
240+
useEffect(() => {
241+
console.log('Effect ran');
242+
const timer = setInterval(() => {
243+
setCount(c => c + 1);
244+
}, 1000);
245+
246+
console.log('Cleanup registered');
247+
return () => {
248+
console.log('Cleanup executed');
249+
clearInterval(timer);
250+
};
251+
}, []);
252+
253+
return <div>Count: {count}</div>;
254+
}
255+
```
256+
257+
- 1: "Effect ran", "Cleanup registered", "Cleanup executed" (on mount), "Cleanup executed" (on unmount)
258+
- 2: "Effect ran", "Cleanup registered" (on mount), "Cleanup executed" (on unmount)
259+
- 3: "Effect ran" (on mount), "Cleanup executed" (on unmount)
260+
- 4: "Effect ran", "Cleanup registered", "Cleanup executed" (on mount and unmount)
261+
262+
<details><summary><b>Answer</b></summary>
263+
<p>
264+
265+
##### Answer: 2
266+
267+
When a component mounts, React runs the effect function completely, which logs both "Effect ran" and "Cleanup registered". The cleanup function (returned from useEffect) is **not** executed during mount - it's only registered at this point.
268+
269+
The cleanup function executes in two scenarios:
270+
1. **Before re-running the effect** (if dependencies change)
271+
2. **When the component unmounts**
272+
273+
Since the dependency array is empty `[]`, the effect only runs once on mount and never re-runs. Therefore, the cleanup function will only execute when the component unmounts, logging "Cleanup executed" and clearing the interval timer.
274+
275+
This pattern is crucial for preventing memory leaks when using timers, subscriptions, or event listeners in React components.
276+
277+
</p>
278+
</details>
279+
280+
---
281+
282+
**[⬆ Back to Top](#table-of-contents)**
283+
284+
#### 7. What will be the output after clicking the button?
285+
286+
```javascript
287+
import { useState } from 'react';
288+
289+
export default function App() {
290+
const [items, setItems] = useState([1, 2, 3]);
291+
292+
function handleClick() {
293+
items.push(4);
294+
setItems(items);
295+
}
296+
297+
return (
298+
<>
299+
<div>Items: {items.join(', ')}</div>
300+
<button onClick={handleClick}>Add Item</button>
301+
</>
302+
);
303+
}
304+
```
305+
306+
- 1: Items: 1, 2, 3, 4
307+
- 2: Items: 1, 2, 3
308+
- 3: Error: Cannot mutate state directly
309+
- 4: Items: 1, 2, 3, 4, 4 (duplicates on each click)
310+
311+
<details><summary><b>Answer</b></summary>
312+
<p>
313+
314+
##### Answer: 2
315+
316+
React uses `Object.is()` comparison to detect state changes. When you mutate the array directly using `items.push(4)` and then pass the same array reference to `setItems(items)`, React sees it as the same object (same reference) and doesn't trigger a re-render.
317+
318+
To properly update an array in state, you should create a new array:
319+
```javascript
320+
setItems([...items, 4]); // or
321+
setItems(items.concat(4));
322+
```
323+
324+
This is a common mistake that leads to bugs where the UI doesn't update even though the underlying data has changed. Always treat state as immutable in React.
325+
326+
</p>
327+
</details>
328+
329+
---
330+
331+
**[⬆ Back to Top](#table-of-contents)**
332+
333+
#### 8. What is the output after the component mounts?
334+
335+
```javascript
336+
import { useState, useEffect } from 'react';
337+
338+
export default function Counter() {
339+
const [count, setCount] = useState(0);
340+
341+
useEffect(() => {
342+
setCount(1);
343+
});
344+
345+
useEffect(() => {
346+
setCount(2);
347+
}, []);
348+
349+
console.log('Rendered with count:', count);
350+
351+
return <div>Count: {count}</div>;
352+
}
353+
```
354+
355+
- 1: "Rendered with count: 0", "Rendered with count: 2"
356+
- 2: "Rendered with count: 0", "Rendered with count: 1", "Rendered with count: 2"
357+
- 3: Infinite loop / Maximum update depth exceeded error
358+
- 4: "Rendered with count: 0", "Rendered with count: 2", "Rendered with count: 1"
359+
360+
<details><summary><b>Answer</b></summary>
361+
<p>
362+
363+
##### Answer: 3
364+
365+
This code creates an **infinite loop** because the first `useEffect` has no dependency array, which means it runs after **every render**. Here's what happens:
366+
367+
1. Initial render with `count: 0`
368+
2. After render, both effects run (first sets count to 1, second sets count to 2)
369+
3. State update triggers re-render with `count: 2`
370+
4. After render, the first effect runs again (no dependencies), setting count to 1
371+
5. This triggers another re-render, and the cycle continues infinitely
372+
373+
React will detect this and throw an error: **"Maximum update depth exceeded"**.
374+
375+
The fix is to add a dependency array to the first useEffect:
376+
```javascript
377+
useEffect(() => {
378+
setCount(1);
379+
}, []); // Add empty dependency array
380+
```
381+
382+
</p>
383+
</details>
384+
385+
---
386+
387+
**[⬆ Back to Top](#table-of-contents)**
388+
389+
#### 9. What will be displayed on the screen?
390+
391+
```javascript
392+
import { useMemo } from 'react';
393+
394+
export default function App() {
395+
const expensiveCalculation = useMemo(() => {
396+
console.log('Calculating...');
397+
return 100 + 200;
398+
});
399+
400+
return <div>Result: {expensiveCalculation}</div>;
401+
}
402+
```
403+
404+
- 1: Result: 300
405+
- 2: Result: function() { ... }
406+
- 3: Result: undefined
407+
- 4: Error: useMemo requires a dependency array
408+
409+
<details><summary><b>Answer</b></summary>
410+
<p>
411+
412+
##### Answer: 4
413+
414+
The `useMemo` hook **requires** a dependency array as the second argument. Without it, React will throw an error during development:
415+
416+
```
417+
Error: useMemo requires a dependency array as the second argument
418+
```
419+
420+
The correct usage is:
421+
```javascript
422+
const expensiveCalculation = useMemo(() => {
423+
console.log('Calculating...');
424+
return 100 + 200;
425+
}, []); // Dependency array is required
426+
```
427+
428+
With an empty dependency array `[]`, the calculation runs once during the initial render and the memoized value (300) is reused on subsequent renders. If you include dependencies, the calculation re-runs whenever those dependencies change.
429+
430+
</p>
431+
</details>
432+
433+
---
434+
435+
**[⬆ Back to Top](#table-of-contents)**
436+
437+
#### 10. What is the output after clicking the button twice?
438+
439+
```javascript
440+
import { useState } from 'react';
441+
442+
export default function Form() {
443+
const [person, setPerson] = useState({
444+
name: 'John',
445+
age: 30
446+
});
447+
448+
function handleClick() {
449+
person.age = person.age + 1;
450+
setPerson(person);
451+
}
452+
453+
return (
454+
<>
455+
<div>Age: {person.age}</div>
456+
<button onClick={handleClick}>Increment Age</button>
457+
</>
458+
);
459+
}
460+
```
461+
462+
- 1: Age: 32
463+
- 2: Age: 31
464+
- 3: Age: 30
465+
- 4: Error: Cannot mutate state
466+
467+
<details><summary><b>Answer</b></summary>
468+
<p>
469+
470+
##### Answer: 3
471+
472+
Similar to the array mutation issue, directly mutating an object's property and then passing the same object reference to the state setter doesn't trigger a re-render. React uses `Object.is()` to compare the old and new state values. Since `person` is still the same object reference, React doesn't detect any change.
473+
474+
Even though `person.age` is being incremented internally, the UI shows the initial value (30) because React never re-renders the component.
475+
476+
The correct approach is to create a new object:
477+
```javascript
478+
function handleClick() {
479+
setPerson({
480+
...person,
481+
age: person.age + 1
482+
});
483+
}
484+
```
485+
486+
This creates a new object with a new reference, which React recognizes as a state change and triggers a re-render. This is a fundamental principle in React: **always treat state as immutable**.
487+
488+
</p>
489+
</details>
490+
491+
---
492+
493+
**[⬆ Back to Top](#table-of-contents)**
494+
495+
#### 11. What will be logged to the console?
496+
497+
```javascript
498+
import { useEffect, useState } from 'react';
499+
500+
export default function App() {
501+
const [count, setCount] = useState(0);
502+
503+
useEffect(() => {
504+
console.log('Effect A');
505+
return () => console.log('Cleanup A');
506+
}, [count]);
507+
508+
useEffect(() => {
509+
console.log('Effect B');
510+
return () => console.log('Cleanup B');
511+
}, []);
512+
513+
console.log('Render');
514+
515+
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
516+
}
517+
```
518+
519+
**On initial mount:**
520+
- 1: "Render", "Effect A", "Effect B"
521+
- 2: "Effect A", "Effect B", "Render"
522+
- 3: "Render", "Effect B", "Effect A"
523+
- 4: "Effect A", "Cleanup A", "Effect B", "Render"
524+
525+
**After first button click:**
526+
- 1: "Render", "Cleanup A", "Effect A"
527+
- 2: "Cleanup A", "Render", "Effect A"
528+
- 3: "Render", "Effect A", "Cleanup A"
529+
- 4: "Render", "Cleanup B", "Effect B", "Cleanup A", "Effect A"
530+
531+
<details><summary><b>Answer</b></summary>
532+
<p>
533+
534+
##### Answer for initial mount: 1, Answer for first click: 1
535+
536+
**On initial mount:**
537+
1. Component renders first: "Render"
538+
2. After render, effects run in the order they're defined: "Effect A", "Effect B"
539+
3. Cleanup functions are registered but not executed
540+
541+
**After first button click:**
542+
1. State changes, component re-renders: "Render"
543+
2. Before running Effect A again (because `count` dependency changed), its cleanup runs: "Cleanup A"
544+
3. Effect A runs again: "Effect A"
545+
4. Effect B doesn't run because its dependency array `[]` is empty (no changes)
546+
5. Cleanup B is not called because Effect B doesn't re-run
547+
548+
**Key takeaways:**
549+
- Render happens first, then effects run
550+
- Effects run in the order they're defined
551+
- Cleanup runs before re-running an effect (when dependencies change)
552+
- Effects with empty dependency arrays only run once on mount
553+
554+
</p>
555+
</details>
556+
557+
---
558+
559+
**[⬆ Back to Top](#table-of-contents)**

0 commit comments

Comments
 (0)