React components are functions that return JSX.
Props are how parent → child communication happens.
► src/components/Greeting.jsx
export default function Greeting({ name, age }) {
return <p>{name} is {age} years old.</p>;
}
Here: name & age are props
Destructuring props: Instead of Greeting(props) we use: Greeting({ name, age })
► usage in App.jsx
import Greeting from './components/Greeting';
export default function App() {
return (
<div>
<Greeting name="Ava" age={28} />
<Greeting name="Sam" age={34} />
</div>
);
}
Example with all types:
<App>
<Profile
user={{ name: "Sam", role: "Admin" }}
skills={["React", "Node", "CSS"]}
handleClick={() => alert("Clicked!")}
/>
</App>
React state is how a component remembers information between renders.
In functional components, the most common way to use state is with the useState hook.
import { useState } from "react";
It returns two things:
The state value
A function to update the value
const [count, setCount] = useState(0);
count → current value
setCount → function that updates the value
0 → initial value
Example: Counter (can be placed in its own file: Counter.jsx)
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count is {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
How it works:
Start with count = 0
When button is clicked → setCount(count + 1)
React re-renders → UI shows new count
const [name, setName] = useState("");
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
Important: Updating objects requires copying the old value.
const [user, setUser] = useState({ name: "Alex", age: 25 });
setUser({ ...user, age: 26 });
const [items, setItems] = useState([]);
setItems([...items, "New item"]);
const [isOpen, setIsOpen] = useState(false);
<button onClick={() => setIsOpen(prev => !prev)}>
{isOpen ? "Close" : "Open"}
</button>
useState(initial) — Creates state value
[value, setValue]— Pair returned by useState
Updating state — Always use setter function
Rerender — Happens every time state updates
❌ count++
❌ user.age = 30
Always use setter:
✅ setUser({ ...user, age: 30 })
setCount(count + 1);
setCount(count + 1);
Both use the same old value.
Use the functional update instead:
setCount(prev => prev + 1);
setCount(prev => prev + 1);
Now it increases by 2.