So, you've run npx create-react-app
and you're staring at a blank App.js
file. What now?
Before you can build a complex project, you must master the three fundamental pillars that make React a powerful and elegant library. If you understand these concepts deeply, you can build almost anything. If you skim over them, you'll always feel like you're just following a recipe without knowing how to cook.
This guide is designed to give you that deep understanding. We will explore, in isolation:
- Pillar 1: Props - How components communicate and are configured.
- Pillar 2: State & Events - How components become interactive and manage memory.
- Pillar 3: Dynamic Lists & Keys - How to render data from a collection.
For each pillar, we'll cover the theory, walk through a simple example, and then you'll solve a quick exercise to solidify your knowledge. Finally, we will combine everything into a complete, final project: an interactive e-commerce product page.
Let's begin.
Pillar 1: Props - The Art of Component Configuration
What are Props, Really?
Props (short for "properties") are the way you pass data from a parent component down to a child component. Think of a React component as a JavaScript function. Props are its arguments. They allow the parent to configure the child, making the child component flexible and highly reusable.
The Golden Rule: Unidirectional Data Flow
This is a core principle of React. Data flows in one direction: downwards, from parent to child. A child component receives props and can use them, but it can never change the props it receives. This "read-only" nature prevents chaos in your application. Imagine if a child component could change its parent's data—it would be impossible to track where changes are coming from! Data flows down like a waterfall, which makes your app predictable and easier to debug.
Code Example: A Configurable WelcomeBanner
Let's create a banner that can be customized for any user.
-
Create a new component file:
src/WelcomeBanner.js
.
// src/WelcomeBanner.js import React from 'react'; const WelcomeBanner = ({ user, theme }) => { const style = { border: `2px solid ${theme === 'dark' ? '#FFFFFF' : '#000000'}`, backgroundColor: theme === 'dark' ? '#2c3e50' : '#ecf0f1', color: theme === 'dark' ? '#FFFFFF' : '#000000', padding: '20px', margin: '10px', borderRadius: '8px', textAlign: 'center', }; return ( <div style={style}> <h1>Welcome back, {user}!</h1> <p>We're so glad to have you here.</p> </div> ); }; export default WelcomeBanner;
-
Now, let's use this component in
App.js
. First, clear out yourApp.js
file, then use this:
// src/App.js import WelcomeBanner from './WelcomeBanner'; function App() { return ( <div> <h1>My Application</h1> <WelcomeBanner user="Alice" theme="light" /> <WelcomeBanner user="Bob" theme="dark" /> </div> ); } export default App;
Notice how
App.js
"configures" eachWelcomeBanner
by passing different props. This is a perfect separation of concerns.
Your Turn: Exercise 1
The Goal: Create a Book
component that displays information about a book. It should accept three props: title
, author
, and pages
.
Click here for the detailed solution
Solution for src/Book.js
:
import React from 'react';
const Book = ({ title, author, pages }) => {
return (
<h3>{title}</h3>
<p>By: {author}</p>
<p>Pages: {pages}</p>
);
};
export default Book;
Solution for src/App.js
:
import Book from './Book';
function App() {
return (
<h1>My Library</h1>
);
}
Pillar 2: State & Events - Giving Components a Memory
What is State?
If props are data passed into a component from a parent, state is the data that a component manages itself. It's the component's private, internal memory. The key feature of state is that when it changes, React automatically re-renders the component to reflect that change.
The useState
Hook: A Deep Dive
We manage state with a Hook. The most essential hook is useState
. Let's break down this line:
const [value, setValue] = useState(initialValue);
-
useState(initialValue)
: The hook call. You pass the initial value of your state. It returns an array with exactly two items. -
const [value, setValue] = ...
: We use "array destructuring" to get those two items. -
value
: The current value of your state. It's read-only. -
setValue
: The updater function. This is the only way you should ever change your state.
Events (onClick
, onChange
, etc.) are the triggers that typically call these updater functions.
Code Example: An Interactive Text Field
-
Create a new component:
src/LiveInput.js
.
// src/LiveInput.js import React, { useState } from 'react'; const LiveInput = () => { const [text, setText] = useState(''); const handleInputChange = (event) => { setText(event.target.value); }; return ( <div style={{ border: '1px solid #8e44ad', padding: '20px', margin: '10px' }}> <input type="text" value={text} onChange={handleInputChange} placeholder="Type here..." /> <p>Current text: <strong>{text}</strong></p> </div> ); }; export default LiveInput;
-
Use it in
App.js
:
// src/App.js import LiveInput from './LiveInput'; function App() { return ( <div> <h1>Understanding State and Events</h1> <LiveInput /> </div> ); }
Your Turn: Exercise 2
The Goal: Create a ToggleVisibility
component. When a button is clicked, some text should hide or show itself.
The Hint: Use a boolean state (isVisible
). The button's onClick
handler will toggle this boolean using setIsVisible(!isVisible)
. Then use conditional rendering: {isVisible && <p>Visible Text!</p>}
.
Click here for the detailed solution
Solution for src/ToggleVisibility.js
:
import React, { useState } from 'react';
const ToggleVisibility = () => {
const [isVisible, setIsVisible] = useState(true);
const handleToggle = () => setIsVisible(!isVisible);
return (
{isVisible ? 'Hide Text' : 'Show Text'}
{isVisible && <p>You can see me!</p>}
);
};
export default ToggleVisibility;
Pillar 3: Dynamic Lists & The Importance of Keys
Real applications render data from collections, usually an array from an API. The standard way to do this in React is with the JavaScript .map()
method.
The key
Prop: Why It's VITAL
When you render a list, you must provide a special key
prop to the top-level element inside the map.
{items.map(item => <li key={item.id}>{item.name}</li>)}
The key
must be a unique and stable identifier. It helps React efficiently update the list without bugs. The best key is always a unique ID from your data, like item.id
.
Code Example: A List of Tech Products
-
Create
src/ProductList.js
.
// src/ProductList.js import React from 'react'; const products = [ { id: 'p1', name: 'Laptop', price: 1200 }, { id: 'p2', name: 'Keyboard', price: 75 }, { id: 'p3', name: 'Mouse', price: 25 }, ]; const ProductList = () => { return ( <div style={{ border: '1px solid #16a085', padding: '20px', margin: '10px' }}> <h2>Products</h2> <ul> {products.map(product => ( <li key={product.id}> {product.name} - ${product.price} </li> ))} </ul> </div> ); }; export default ProductList;
-
Use it in
App.js
:
// src/App.js import ProductList from './ProductList'; function App() { return ( <div> <h1>Rendering Lists</h1> <ProductList /> </div> ); }
Your Turn: Exercise 3
The Goal: Create a TeamMemberList
component that renders an ordered list (<ol>
) of team members from an array of objects (each with an id
, name
, and role
).
Click here for the detailed solution
Solution for src/TeamMemberList.js
:
import React from 'react';
const teamMembers = [
{ id: 101, name: 'Alex Johnson', role: 'Lead Developer' },
{ id: 102, name: 'Maria Garcia', role: 'UI/UX Designer' },
{ id: 103, name: 'James Smith', role: 'Project Manager' },
];
const TeamMemberList = () => {
return (
<h2>Our Team</h2>
<ol>
{teamMembers.map(member => (
<li>
<strong>{member.name}</strong> - {member.role}
</li>
))}
</ol>
);
};
export default TeamMemberList;
The Final Project: Build an Interactive Product Page
You've mastered the core concepts. Now, let's prove it by building a complete, interactive application that combines everything you've learned: a Simple E-commerce Product Page.
Step 1: Plan Your Components
-
App.js
: The parent. It will hold thecartCount
state. -
Header.js
: Displays the cart count. -
ProductDisplay.js
: Shows the product and has the "Add to Cart" button. -
Reviews.js
: Renders a list of product reviews.
Step 2: Set Up Your Project
- Clear your
src
folder of the exercise files. - Create a
components
folder and addHeader.js
,ProductDisplay.js
, andReviews.js
inside it. - Create a
ProductPage.css
file insrc
.
Step 3: Build the App
Component (The Central Hub)
App.js
will manage the cart state and pass down data and functions.
// src/App.js
import React, { useState } from 'react';
import Header from './components/Header';
import ProductDisplay from './components/ProductDisplay';
import Reviews from './components/Reviews';
import './ProductPage.css';
const productData = {
title: 'React Performance Sneakers',
price: 120.00,
imageUrl: 'https://via.placeholder.com/400x400.png?text=React+Sneakers',
};
const reviewsData = [
{ id: 1, author: 'Alex', text: 'Amazing shoes, so comfortable!' },
{ id: 2, author: 'Maria', text: 'Great for running, highly recommend.' },
];
function App() {
const [cartCount, setCartCount] = useState(0);
const handleAddToCart = () => setCartCount(cartCount + 1);
return (
<div className="app-container">
<Header cartCount={cartCount} />
<main>
<ProductDisplay
product={productData}
onAddToCart={handleAddToCart}
/>
<Reviews reviews={reviewsData} />
</main>
</div>
);
}
export default App;
Key Concept: Lifting State Up: The
cartCount
state lives inApp.js
because multiple children need to interact with it. The parent owns the state and passes down the value and the updater function as props.
Step 4: Build the Child Components
Header.js
:
// src/components/Header.js
import React from 'react';
const Header = ({ cartCount }) => (
<header className="app-header">
<h1>React Shoe Store</h1>
<div className="cart-widget"><span>Cart: {cartCount}</span></div>
</header>
);
export default Header;
ProductDisplay.js
:
// src/components/ProductDisplay.js
import React from 'react';
const ProductDisplay = ({ product, onAddToCart }) => {
const { title, price, imageUrl } = product;
return (
<div className="product-display">
<img src={imageUrl} alt={title} className="product-image" />
<div className="product-info">
<h2>{title}</h2>
<p className="product-price">${price.toFixed(2)}</p>
<button className="add-to-cart-btn" onClick={onAddToCart}>Add to Cart</button>
</div>
</div>
);
};
export default ProductDisplay;
Reviews.js
:
// src/components/Reviews.js
import React from 'react';
const Reviews = ({ reviews }) => (
<section className="reviews-section">
<h3>Customer Reviews</h3>
{reviews.map(review => (
<div key={review.id} className="review-card">
<strong>{review.author} says:</strong>
<p>"{review.text}"</p>
</div>
))}
</section>
);
export default Reviews;
Step 5: Bringing It All Together with CSS
Create src/ProductPage.css
and add these styles.
/* src/ProductPage.css */
body { font-family: sans-serif; background-color: #f7f7f7; margin: 0; }
.app-container { max-width: 900px; margin: 0 auto; background-color: #fff; box-shadow: 0 0 20px rgba(0,0,0,0.05); }
.app-header { display: flex; justify-content: space-between; align-items: center; padding: 1rem 2rem; background-color: #2c3e50; color: white; }
.app-header h1 { font-size: 1.5rem; margin: 0; }
.cart-widget { font-weight: bold; }
main { padding: 2rem; }
.product-display { display: flex; gap: 2rem; border-bottom: 1px solid #eee; padding-bottom: 2rem; margin-bottom: 2rem; }
.product-image { max-width: 400px; border-radius: 8px; border: 1px solid #ddd; }
.product-info h2 { margin-top: 0; font-size: 2rem; }
.product-price { font-size: 1.5rem; color: #27ae60; font-weight: bold; margin: 1rem 0; }
.add-to-cart-btn { background-color: #3498db; color: white; border: none; padding: 15px 25px; font-size: 1rem; font-weight: bold; border-radius: 5px; cursor: pointer; transition: background-color 0.3s; }
.add-to-cart-btn:hover { background-color: #2980b9; }
.reviews-section h3 { font-size: 1.5rem; }
.review-card { background-color: #f9f9f9; border-left: 4px solid #3498db; padding: 1rem; margin-bottom: 1rem; border-radius: 4px; }
.review-card p { margin-top: 0.5rem; font-style: italic; }
Run your app (npm start
) and test it out! Click the "Add to Cart" button and watch the number in the header update. You have just built a fantastic, interactive React application from the ground up.
You Are Now a React Developer
You have successfully progressed from learning isolated concepts to building a complete, cohesive application. You understand how data flows through a React app, how to manage its internal state, and how to render dynamic content.
You are now fully prepared to tackle any project you can imagine. Take this foundation and start building!
Happy coding!
Top comments (0)