Splitting Components β Props & Event Callbacks | Tutorial
\\n\\nComponent-based architecture is the core design philosophy of React. In this chapter, you will learn how to break a page into reusable small components, and implement parent-child communication through Props and callback functions.
\\n\\n\\n\\n
Why Split Components?
\\n\\nApp.jsx is getting longer and longer, with hundreds of lines of code crammed together, making it difficult to maintain and reuse.
\\n\\nPrinciple of splitting components: Each component is responsible for only one thing, and they are combined to accomplish complex functionality.
\\n\\nWhat Granularity is Appropriate?
\\n\\n| Page Area | \\nShould It Be a Component? | \\nReason | \\n
|---|---|---|
| Navigation bar | \\nYes | \\nNeeded on every page, independent functionality | \\n
| Article card | \\nYes | \\nEach item in the list shares the same structure | \\n
| Category filter button group | \\nYes | \\nHas its own state and interactions | \\n
| Simple wrapper container | \\nNo | \\nJust for layout, no independent behavior | \\n
\\n\\n
Parent to Child: Props
\\n\\nIn React, Props are the arguments of a function β when a parent component calls a child component, it passes data in through attributes.
\\n\\nExample
\\n\\n// File path: src/components/BlogCard.jsx\\n\\n// Props is the first argument of the function, usually destructured\\n\\nfunction BlogCard({ title, summary, date, category }){\\n return(\\n <div className="card">\\n <span className="tag">{category}</span>\\n <h3>{title}</h3>\\n <p>{summary}</p>\\n <span className="date">{date}</span>\\n </div>\\n )\\n}\\n\\nexport default BlogCard\\n\\nThe parent component passes data in like writing HTML attributes:
\\n\\nExample
\\n\\n// File path: src/App.jsx\\n\\nimport BlogCard from './components/BlogCard'\\n\\nfunction App(){\\n const articles = [\\n { id: 1, title: 'React Getting Started', summary: 'Learn React from Scratch', date: '2024-05-10', category: 'React' },\\n { id: 2, title: 'Promise Detailed Explanation', summary: 'Understanding Async', date: '2024-05-08', category: 'JavaScript' },\\n ]\\n\\n return(\\n <div className="article-grid">\\n {articles.map(article => (\\n <BlogCard\\n key={article.id}\\n title={article.title}\\n summary={article.summary}\\n date={article.date}\\n category={article.category}\\n />\\n ))}\\n </div>\\n )\\n}\\n\\n\\n\\n\\nProps follow a unidirectional data flow: data flows from parent components to child components. Child components cannot modify the Props they receive. If modification is needed, it should be handled by the parent component through a callback function.
\\n
\\n\\n
Child to Parent: Callback Functions
\\n\\nWhen a child component needs to notify the parent component that "something happened," the parent component needs to pass a callback function as a Prop.
\\n\\nExample
\\n\\n// File path: src/components/CategoryFilter.jsx\\n\\nfunction CategoryFilter({ categories, activeCategory, onCategoryChange }){\\n return(\\n <div className="filter-bar">\\n {categories.map(cat => (\\n <button\\n key={cat}\\n className={activeCategory === cat ? 'active' : ''}\\n // Call the callback function passed from parent when clicked\\n onClick={() => onCategoryChange(cat)}\\n >\\n {cat}\\n </button>\\n ))}\\n </div>\\n )\\n}\\n\\nexport default CategoryFilter\\n\\nThe parent component passes the callback function:
\\n\\nExample
\\n\\nimport { useState } from 'react'\\nimport CategoryFilter from './components/CategoryFilter'\\n\\nfunction App(){\\n const [activeCategory, setActiveCategory] = useState('All')\\n const categories = ['All', 'React', 'JavaScript', 'CSS']\\n\\n // Callback function: responds to click events from child component\\n function handleCategoryChange(cat){\\n setActiveCategory(cat)\\n }\\n\\n return(\\n <CategoryFilter\\n categories={categories}\\n activeCategory={activeCategory}\\n onCategoryChange={handleCategoryChange}\\n />\\n )\\n}\\n\\nReact vs Vue3 Communication Comparison
\\n\\n| Scenario | \\nVue3 | \\nReact | \\n
|---|---|---|
| Parent to child | \\nProps (defineProps) | \\nProps (function arguments) | \\n
| Child to parent | \\nemit events | \\nProps callback functions | \\n
| Data direction | \\nUnidirectional | \\nUnidirectional | \\n
Vue3 uses the emit mechanism, React uses callback functions β the essence is the same, only the syntax differs.
\\n\\n\\n\\n
Props Destructuring and Default Values
\\n\\nExample
\\n\\n// Props with default values\\n\\nfunction BlogCard({\\n title = 'Untitled Post', // ES6 destructuring default value\\n summary = 'No Summary Available',\\n date = '',\\n category = 'Uncategorized'\\n}){\\n return(\\n <div className="card">\\n <span className="tag">{category}</span>\\n <h3>{title}</h3>\\n <p>{summary}</p>\\n {date && <span className="date">{date}</span>}\\n </div>\\n )\\n}\\n\\n\\n\\n
Hands-on: Extract Three Components
\\n\\nThe component structure of the blog project is as follows:
\\n\\nsrc/\\nβββ components/\\nβ βββ NavBar.jsx # Top navigation bar\\nβ βββ BlogCard.jsx # Single article card\\nβ βββ CategoryFilter.jsx # Category filter button group\\nβββ App.jsx\\n\\nNavBar.jsx
\\n\\nExample
\\n\\n// File path: src/components/NavBar.jsx\\n\\nimport '../App.css'\\n\\nfunction NavBar(){\\n return(\\n <header className="navbar">\\n <a href="/" className="logo">TUTORIAL Blog</a>\\n <nav>\\n <a href="/">Home</a>\\n <a href="#">About</a>\\n </nav>\\n </header>\\n )\\n}\\n\\nexport default NavBar\\n\\nApp.jsx β Integrating All Components
\\n\\nExample
\\n\\n// File path: src/App.jsx\\n\\nimport { useState, useMemo } from 'react'\\nimport NavBar from './components/NavBar'\\nimport BlogCard from './components/BlogCard'\\nimport CategoryFilter from './components/CategoryFilter'\\nimport './App.css'\\n\\nfunction App(){\\n const = useState([\\n { id: 1, title: 'React Getting StartedComplete Guide', summary: 'Learn React Hooks from Scratch', date: '2024-05-10', category: 'React' },\\n { id: 2, title: 'JS Asynchronous Programming Detailed Explanation', summary: 'Understanding Promise and async/await', date: '2024-05-08', category: 'JavaScript' },\\n { id: 3, title: 'CSS Grid Layout in Practice', summary: 'Use Grid Implementing Responsive Layout', date: '2024-05-05', category: 'CSS' },\\n { id: 4, title: 'React Hooks Deep Dive', summary: 'Deep DiveUnderstanding useState and useEffect', date: '2024-05-03', category: 'React' },\\n { id: 5, title: 'Flexbox Complete Guide', summary: 'Master Flexbox in One Tutorial', date: '2024-05-01', category: 'CSS' },\\n ])\\n\\n const [activeCategory, setActiveCategory] = useState('All')\\n\\n const categories = useMemo(() => {\\n const cats = articles.map(a => a.category)\\n return ['All', ...new Set(cats)]\\n }, )\\n\\n const filteredArticles = useMemo(() => {\\n if (activeCategory === 'All') return articles\\n return articles.filter(a => a.category === activeCategory)\\n }, [articles, activeCategory])\\n\\n return(\\n <div className="app">\\n <NavBar />\\n <main className="container">\\n <h2 className="section-title">Latest Posts</h2>\\n {/* Child component: receives props (categories, activeCategory) and callback (onCategoryChange) */}\\n <CategoryFilter\\n categories={categories}\\n activeCategory={activeCategory}\\n onCategoryChange={setActiveCategory}\\n />\\n <p className="result-info">Total {filteredArticles.length} posts</p>\\n {filteredArticles.length === 0 ? (\\n <p className="empty-tip">No Posts in This Category</p>\\n ) : (\\n <div className="article-grid">\\n {filteredArticles.map(article => (\\n <BlogCard\\n key={article.id}\\n title={article.title}\\n summary={article.summary}\\n date={article.date}\\n category={article.category}\\n />\\n ))}\\n </div>\\n )}\\n </main>\\n <footer className="footer">\\n <p>Β© 2024 TUTORIAL Blog. Powered by React.</p>\\n </footer>\\n </div>\\n )\\n}\\n\\nexport default App\\n\\n\\n\\n
Chapter Summary
\\n\\nIn this chapter, you mastered the core of React component communication: parent to child through Props (function arguments), child to parent through Props callback functions.
\\n\\nThe three components of the blog project β NavBar, BlogCard, and CategoryFilter β are now in place, and the code structure is much cleaner.
YouTip