Components are the heart of React. Once you can split a page into components and pass data between them, you can build almost any screen. This lesson shows how, with small, clear examples.
What is a component?
A component is a JavaScript function that returns JSX. It has a name that starts with a capital letter. You use it like an HTML tag. Components can be used again and again, and they can use other components inside them.
function Greeting() {
return <p>Hello there!</p>;
}
function App() {
return (
<div>
<Greeting />
<Greeting />
<Greeting />
</div>
);
}
This shows the greeting three times. But three identical greetings are not very useful. We want each greeting to show a different name. That is the job of props.
Props: giving data to a component
Props (short for properties) are the inputs of a component, like the arguments of a function. The parent writes them like HTML attributes. The child receives them as one object.
function Greeting(props) {
return <p>Hello, {props.name}! You are {props.age} years old.</p>;
}
function App() {
return (
<div>
<Greeting name="Asha" age={24} />
<Greeting name="Ravi" age={31} />
</div>
);
}
Notice the difference between name="Asha" (text, in quotes) and age={24} (a number, in curly braces). If the value is not a plain string, use curly braces. This is true for numbers, booleans, arrays, objects and functions.
Destructuring props
Writing props.name again and again is long. Most people use destructuring, a JavaScript feature that pulls values out of an object into variables. You do it right in the function brackets:
function Greeting({ name, age }) {
return <p>Hello, {name}! You are {age} years old.</p>;
}
This does exactly the same, and it also shows at the top which props the component needs. We will use this style from now on.
Default values
If a parent forgets to pass a prop, its value is undefined. You can give a default value in the destructuring:
function Button({ label = 'Click me', color = 'blue' }) {
return <button style={{ background: color, color: 'white' }}>{label}</button>;
}
// <Button /> shows "Click me"
// <Button label="Save" color="green" />
Props are read-only
A component must never change its own props. Props belong to the parent. If a child needs data that changes, it uses state, which you will meet in the next lesson. This rule keeps data flow simple: data goes down, and you can always find where a value came from. If you try to assign props.name = 'x', React will give an error.
Passing different kinds of values
<Profile
name="Asha"
isAdmin={true}
skills={['React', 'CSS', 'SQL']}
address={{ city: 'Pune', country: 'India' }}
onSave={() => console.log('saved')}
/>
A prop can be text, a number, a true or false value, an array, an object, or even a function. Passing a function is how a child tells its parent that something happened, as you will see in the lessons on events and lifting state.
For a true prop you can write just the name: <Profile isAdmin /> means the same as isAdmin={true}.
Children: putting content inside a component
Sometimes you want to put things between the opening and closing tags of your component, like you do with a div. React gives these to the component as a special prop called children.
function Card({ title, children }) {
return (
<section className="card">
<h2>{title}</h2>
<div>{children}</div>
</section>
);
}
function App() {
return (
<Card title="Today's tip">
<p>Drink some water.</p>
<button>Done</button>
</Card>
);
}
The Card does not know what is inside it. This makes it a very flexible building block. Boxes, layouts, modals and panels are often made this way.
Splitting a page into components
A good habit: look at a design and draw boxes around the parts that repeat, or that have one clear job. Each box can be a component. Here is a small profile page split into pieces:
function Avatar({ src, name }) {
return <img src={src} alt={name} width="64" height="64" />;
}
function UserInfo({ user }) {
return (
<div>
<Avatar src={user.photo} name={user.name} />
<h3>{user.name}</h3>
<p>{user.job}</p>
</div>
);
}
function App() {
const user = { name: 'Asha', job: 'Designer', photo: '/asha.png' };
return <UserInfo user={user} />;
}
A rule of thumb: if a part of the screen is used in more than one place, or if a function grows over about fifty lines, think about splitting it. Do not split too early either. A tiny component used once is not always better.
Where to put components
- Put each component in its own file, named after it:
Avatar.jsxholdsAvatar. - Use
export default Avatar;at the bottom, andimport Avatar from './Avatar.jsx';at the top of the file that uses it. - Group files in folders such as
src/components. Keep it simple until the project grows.
Never define a component inside another component. It looks like it works, but React will make a new copy on every draw, and any state inside it is lost. Always write components at the top level of a file.
Common mistakes
- Forgetting the capital letter, so
<card>is treated as an HTML tag. - Writing
age="24"and then trying to add to it: it is text, not a number. Useage={24}. - Changing props inside the child. Copy the value into state if you need to change it.
- Defining a component inside another one.
- Passing a function call instead of a function:
onSave={save()}runs it at once. UseonSave={save}oronSave={() => save(id)}.
A complete example, step by step
Let us build a small team page, and watch how props travel. We have three pieces: an App that owns the data, a TeamList that shows many people, and a Person that shows one.
function Person({ name, role }) {
return <li>{name} is a {role}.</li>;
}
function TeamList({ people }) {
return (
<ul>
{people.map((p) => <Person key={p.id} name={p.name} role={p.role} />)}
</ul>
);
}
function App() {
const people = [
{ id: 1, name: 'Asha', role: 'designer' },
{ id: 2, name: 'Ravi', role: 'developer' },
];
return <TeamList people={people} />;
}
Follow the data. App makes the list and passes it to TeamList as the prop people. TeamList goes through the list and, for each item, passes name and role to a Person. Person finally shows them. The data moves down, one level at a time, and nobody changes it on the way. If a name looks wrong on the page, you know to look at the data in App.
Notice how each piece is easy to understand alone. Person knows nothing about teams. You could use it on an about page, in a contact list or in a chat. This is the real power of components: small, simple and used in many places.
Questions beginners often ask
Can a component return nothing? Yes. Return null and it shows nothing. This is useful for a component that decides not to appear, such as a banner with no message.
How do I know when to make a new component? Make one when a piece of the screen repeats, when it has one clear job, or when a component becomes hard to read. If you can give a part a good short name, such as Avatar or PriceTag, it is a good candidate.
Why is my component name in capital letters? It is how React tells your own components from HTML tags. <card /> is looked up as an HTML tag called card, but <Card /> is your function.
Can props have the same name as HTML attributes? Yes. Props are your own names. Many people use title, src and label. Just remember that a prop does nothing until your component uses it.
Your task
- Create a
ProductCardcomponent that takesname,priceand an optionalinStockprop (defaulttrue). Show “Out of stock” when it is false. - Use it three times with different data.
- Create a
Boxcomponent that wraps itschildrenin a border, and put aProductCardinside it.
How to check it worked
- Three different cards appear on the page.
- Changing
inStocktofalsechanges the message. - The
Boxdraws a border around any content you put inside.
Summary
- A component is a function with a capital letter that returns JSX.
- Props are read-only inputs. Use destructuring, defaults and curly braces for non-text values.
childrenis the content placed inside a component's tags.- Split the screen into small pieces, each in its own file, and never define a component inside another.