In this article, we will deeply dive into React JS components and props, explaining what they are, how they work, and how you can leverage them effectively in your React applications.
Introduction to React Components and Props
When building applications in React, understanding components and props is crucial. Components are the building blocks of React applications. Think of them as JavaScript functions that return a piece of UI. Props, short for properties, allow you to pass data from one component to another.
By mastering these two concepts, you can build highly efficient, scalable, and maintainable applications.
What is a React Component?
A React component is simply a JavaScript function (or class) that returns a React element. It’s a piece of UI, often encapsulated with logic and styles, that can be reused throughout an application. Components can be as simple as a button or as complex as an entire page.
Here’s a basic example of a React component:
function MyComponent() {
return <h1>Hello, World!</h1>;
}
n this case, MyComponent is a simple function that returns a header element.
Functional vs. Class Components
React provides two ways to define components: functional components and class components.
Functional Components: These are simple JavaScript functions that return JSX.
function Greeting() {
return <h1>Hello, User!</h1>;
}
Class Components: These are ES6 classes that extend the React.Component
class and include a render()
method to return JSX.
class Greeting extends React.Component {
render() {
return <h1>Hello, User!</h1>;
}
}
Functional components are more common in modern React due to their simplicity and the introduction of React Hooks.
Where to Render the Component
To display a React component in the browser, you need to render it inside a root element in the DOM. The ReactDOM.render()
method is used for this purpose.
First Approach (Modern Method):
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<HookTimer />
</React.StrictMode>
);
- React 18+: This method is part of React 18’s new root API, which supports concurrent rendering features.
- Strict Mode: Using
<React.StrictMode>
is a good practice as it helps detect potential problems in your application. - Performance Benefits: The new root API is designed to support future improvements in performance and rendering behavior.
Second Approach (Old Method):
import ReactDOM from 'react-dom';
ReactDOM.render(<MyComponent />, document.getElementById('root'));
- Legacy Method: This method is part of React’s legacy
render()
API, which is still functional but will be deprecated in future versions. - Doesn’t support concurrent rendering: It does not take advantage of the latest React features introduced in version 18, such as concurrent rendering.
The first approach using ReactDOM.createRoot()
is better because it is future-proof, provides better performance, and supports new features introduced in React 18+. The second approach works for older versions but is being phased out.
Creating Multiple And Nested Components in React
In a real-world application, you will rarely have just one component. You’ll typically create multiple components and organize them across different files.
ExternalComponent.js (An external reusable component)
// ExternalComponent.js
import React from 'react';
function ExternalComponent() {
return <h2>This is an external reusable component</h2>;
}
export default ExternalComponent;
MainComponent.js (Main Component with Nested Components)
// MainComponent.js
import React from "react";
import ExternalComponent from "./ExternalComponent";
function MainComponent() {
return (
<div>
<ExternalComponent /> {/* Using the external component */}
<h1>Main Component: Welcome to the app!</h1>
{/* Rendering NestedComponent */}
<NestedComponent />
{/* Rendering Footer component */}
<Footer />
</div>
);
}
function NestedComponent() {
return (
<div>
<h2>Nested Component: Here are more details</h2>
{/* Rendering another nested component */}
<InnerComponent />
</div>
);
}
function InnerComponent() {
return <h3>Inner Component: Deep inside the nested structure!</h3>;
}
function Footer() {
return <footer>Footer: This is the footer section</footer>;
}
export default MainComponent;
index.js (Rendering the MainComponent)
// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import MainComponent from './MainComponent'; // Importing the main component
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<MainComponent /> {/* Rendering the MainComponent */}
</React.StrictMode>
);
Key Points:
ExternalComponent
: A reusable component that can be used in multiple places within your app.MainComponent
: The main component that acts as the entry point, rendering other nested components.NestedComponent
: A child ofMainComponent
with further nesting to showcase how deep component hierarchies can go.InnerComponent
: This component represents the innermost level of the nested structure.Footer
: A simple footer component that provides a closing section.
Props in React
The Importance of Props in React
Props (short for “properties”) are a core concept in React that allow you to pass data from one component to another, typically from parent to child. Props make components reusable and dynamic, allowing different data to be passed to the same component without altering its internal logic.
ParentComponent.js
import React from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
return (
<div>
<h1>Parent Component</h1>
{/* Passing props to the child component */}
<ChildComponent message="Hello from Parent!" />
</div>
);
}
export default ParentComponent;
ChildComponent.js
import React from 'react';
function ChildComponent(props) {
return (
<div>
<h2>Child Component</h2>
{/* Using props to display data */}
<p>{props.message}</p>
</div>
);
}
export default ChildComponent;
In this example, the ParentComponent passes a message prop to the ChildComponent, which uses it to display the message.
Passing Props to Components
Props allow you to pass different types of data (strings, numbers, arrays, objects, functions) to child components. This helps in creating dynamic UIs based on the data passed.
ProductList.js
import React from 'react';
import Product from './Product';
function ProductList() {
const products = [
{ id: 1, name: "Laptop", price: 1200 },
{ id: 2, name: "Phone", price: 800 },
];
return (
<div>
<h1>Product List</h1>
{products.map((product) => (
// Passing multiple props to the Product component
<Product key={product.id} name={product.name} price={product.price} />
))}
</div>
);
}
export default ProductList;
Product.js
import React from 'react';
function Product(props) {
return (
<div>
<h2>{props.name}</h2>
<p>Price: ${props.price}</p>
</div>
);
}
export default Product;
Default Props in React
Default props provide fallback values for props that are not passed to a component. This ensures that a component still works even if certain props are missing.
Greeting.js
import React from 'react';
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Setting default props
Greeting.defaultProps = {
name: 'Guest'
};
export default Greeting;
App.js
import React from 'react';
import Greeting from './Greeting';
function App() {
return (
<div>
{/* Passing a prop */}
<Greeting name="Alice" />
{/* Not passing any prop, will use default */}
<Greeting />
</div>
);
}
export default App;
In this case, when no name prop is passed to the Greeting component, it falls back to the default prop value, “Guest”
Handling Props with Destructuring
Destructuring allows you to extract specific values from an object or array, making it easier to work with props inside a component. This improves readability and reduces repetitive code.
UserProfile.js
mport React from 'react';
function UserProfile({ name, age, email }) {
return (
<div>
<h2>User Profile</h2>
<p>Name: {name}</p>
<p>Age: {age}</p>
<p>Email: {email}</p>
</div>
);
}
export default UserProfile;
App.js
import React from 'react';
import UserProfile from './UserProfile';
function App() {
return (
<div>
<UserProfile name="John Doe" age={30} email="john@example.com" />
</div>
);
}
export default App;
In the UserProfile component, props are destructured directly in the function’s parameter list, making it simpler to reference name, age, and email.
Importance of Props: Props help pass data between components.
Passing Props to Components: You can pass different types of props, enabling dynamic component behavior.
Default Props: Allow fallback values when props are not provided.
Handling Props with Destructuring: Improves readability by extracting specific values from props.
Using React.Fragment Tag Instead of div Tag
In React, components often return multiple elements, which are typically wrapped in a single parent element like <div>
. However, this approach can lead to “div soup” — unnecessary <div>
elements cluttering the DOM structure.
React provides the component (or its shorthand syntax) to avoid adding unnecessary nodes to wrap multiple children without introducing additional DOM elements. This is especially useful for grouping elements without affecting the layout or structure.
Why Use <React.Fragment>?
- Cleaner DOM: It avoids adding extra nodes to the DOM, which can help with styling and performance.
- Semantic HTML: Reduces the number of unnecessary
<div>
elements, helping create a more meaningful and semantic HTML structure. - Performance: Fewer nodes in the DOM can lead to slightly improved performance.
Example 1: Code Using <React.Fragment>:
ItemList.js
// ItemList.js
import React from 'react';
function ItemList() {
return (
<React.Fragment>
<h1>Item List</h1>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
</React.Fragment>
);
}
export default ItemList;
Example 2: Using the Shorthand Syntax (<> </>)
UserDetails.js
// UserDetails.js
import React from 'react';
function UserDetails() {
return (
<>
<h2>User Profile</h2>
<p>Name: Jane Doe</p>
<p>Email: jane.doe@example.com</p>
</>
);
}
export default UserDetails;
Without <React.Fragment> (Using <div>)
For comparison, here’s the same example using a <div>
wrapper:
UserDetails.js (with <div>)
import React from 'react';
function UserDetails() {
return (
<div>
<h2>User Profile</h2>
<p>Name: Jane Doe</p>
<p>Email: jane.doe@example.com</p>
</div>
);
}
export default UserDetails;
In this case, the <div> creates an extra layer in the DOM that isn’t necessary.
When to Use <React.Fragment>:
- When you need to return multiple sibling elements without adding an extra node to the DOM.
- When you want to avoid unnecessary
<div>
wrappers. - When grouping elements inside table rows (
<tr>
) or lists (<ul>
,<ol>
) where additional elements could break layout or styling. <React.Fragment>
allows you to return multiple elements without adding extra nodes to the DOM.- It is useful for cleaner DOM structure and better performance, especially when wrapping elements in non-semantic
<div>
tags is not necessary. - The shorthand syntax
<> </>
can be used for simplicity when no key or attributes are required.
Conclusion
React components and props are the foundation of any React application. By understanding how to create, pass, and manage props in components, you can build dynamic, reusable, and efficient UIs. Components allow you to break down your application into smaller, manageable parts, while props enable you to pass data between those parts, ensuring your UI remains dynamic and flexible.