# React Exercises

## Exercise 1: Toggle Button

**Task:** Create a `Toggle` component that shows "ON" or "OFF" and switches when clicked. Use `useState` with a boolean.

**Validation:**
- [ ] Clicking toggles between ON and OFF
- [ ] The displayed text updates on every click
- [ ] State is managed with a single boolean

**Hints:**
1. `useState(false)` gives you `[value, setValue]`
2. Toggle with `setValue(!value)` or `setValue(prev => !prev)`
3. Use a ternary or template literal for the display text

---

## Exercise 2: Input Mirror

**Task:** Create a component with a text input. Whatever the user types should appear in a `<p>` below in real time (controlled input).

**Validation:**
- [ ] Typing updates the paragraph immediately
- [ ] The input value is controlled by state
- [ ] Clearing the input clears the paragraph

**Hints:**
1. Use `useState("")` for the value
2. `onChange={(e) => setValue(e.target.value)}`
3. `value={value}` makes it a controlled input

---

## Exercise 3: Timer with useEffect

**Task:** Create a timer that counts up every second when mounted. Use `useEffect` with `setInterval`. Clean up the interval when the component unmounts.

**Validation:**
- [ ] The displayed number increments every second
- [ ] No interval leak on unmount (return cleanup from useEffect)
- [ ] Uses `useState` for the displayed count

**Hints:**
1. `useEffect` with `[count]` or `[]` — which do you need?
2. `return () => clearInterval(id)` in the effect
3. `setCount(c => c + 1)` avoids stale closures

---

## Exercise 4: Search Filter

**Task:** Given a static array of names (e.g., `["Alice", "Bob", "Carol", "Dave"]`), render them in a list. Add a search input that filters the list as the user types (case-insensitive).

**Validation:**
- [ ] Typing "al" shows only "Alice"
- [ ] Clearing the input shows all names
- [ ] Filtering is case-insensitive
- [ ] Uses `filter()` and does not mutate the original array

**Hints:**
1. Store the search term in state, not the filtered list
2. Derive filtered list: `names.filter(n => n.toLowerCase().includes(search.toLowerCase()))`
3. The list is derived state — no need for separate state

---

## Exercise 5: Form with Validation

**Task:** Create a simple form with a name input (required) and an email input (required, must contain `@`). Show an error message below each invalid field. Disable the submit button until the form is valid.

**Validation:**
- [ ] Submitting with empty fields shows errors
- [ ] Invalid email format shows an error
- [ ] Submit button is disabled when invalid
- [ ] Valid form enables submit

**Hints:**
1. Track `name`, `email`, and optionally `touched` / `errors` in state
2. Compute validity: `name.trim() && email.includes('@')`
3. Optionally show errors only after first submit or on blur
