Hello, everyone! I'm back to discuss the core concepts of React from before hooks were introduced. There's a famous saying: "Those who do not know history are doomed to repeat it." Similarly, to create the best React applications, understanding its foundational concepts is essential.
Here are the concepts we will be discussing today:
Fragments
Pure Components
Memo
Refs
Portals
Let's understand each concept with code snippets.
1. Fragments: In React, fragments are a way to group multiple elements without adding an extra HTML element to the DOM.
This will be very help full while dealing with the tables
a. Avoiding extra DOM nodes.
//Example without Fragments
function TableHeader() {
return (
<div> {/* Invalid because <thead> requires direct child <tr> */}
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</div>
);
}
//Example with Fragments
function TableHeader() {
return (
<>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
</>
);
}
b. Grouping Multiple Elements Without Adding Extra Wrappers.
function TableBody() {
return (
<>
<tr><td>Row 1</td><td>Data</td></tr>
<tr><td>Row 2</td><td>Data</td></tr>
</>
);
}
c. Handling Lists and .map()
function ItemList() {
const items = ['Apple', 'Banana', 'Orange'];
return (
<ul>
{items.map((item, index) => (
<React.Fragment key={index}>
<li>{item}</li>
</React.Fragment>
))}
</ul>
);
}
d. When You Need to Return Multiple Elements from a Component
function HeaderFooter() {
return (
<>
<header>
<h1>Welcome</h1>
</header>
<footer>
<p>Contact us</p>
</footer>
</>
);
}
e. Conditional Rendering
function MyComponent({ showFooter }) {
return (
<>
<h1>Hello</h1>
{showFooter && <footer>Footer Content</footer>}
</>
);
}
Pure Components:
A normal component in React is a component that doesn't implement any special optimizations for re-rendering. React will re-render this component every time its parent component re-renders, regardless of whether its props or state have changed.
class RegularComponent extends React.Component {
render() {
console.log("Regular Component Rendered");
return <div>{this.props.name}</div>;
}
}
Every time the parent of RegularComponent
re-renders, the RegularComponent
will also re-render, even if the props
or state
passed to it haven't changed.
A Pure Component is a component that only re-renders if its props
or state
have changed. It performs a shallow comparison of the previous and current props
and state
. If there are no changes, it skips the re-rendering process, which can improve performance, especially in large applications with many components.
Pure components are created by extending React.PureComponent
, which automatically implements a shouldComponentUpdate()
method that performs a shallow comparison of props and state.
class PureComponentExample extends React.PureComponent {
render() {
console.log("Pure Component Rendered");
return <div>{this.props.name}</div>;
}
}
In the above example, PureComponentExample
will only re-render if the props
or state
have actually changed. If the name
prop passed into it remains the same between renders, the component will not re-render, saving resources.
Let’s understand shallow and deep comparison:
Shallow Comparison (used by
React.PureComponent
): React compares the top-level properties or values ofprops
andstate
(no deep comparison). For objects/arrays, it checks if the reference has changed.Deep Comparison (not used by default): React would compare the nested properties or values inside objects and arrays recursively. This would be much more expensive performance-wise, so React uses shallow comparison for efficiency.
- Memo:
React.memo
is a higher-order component (HOC) that is used to wrap a functional component and optimize its re-rendering. When a component is wrapped withReact.memo
, React will only re-render the component if its props change. If the props remain the same, React will skip the re-render, improving performance by avoiding unnecessary updates.
PureComponents are for class components, and memo is for functional components.
function MyComponent({ name }) {
console.log("Component re-rendered");
return <div>{name}</div>;
}
export default React.memo(MyComponent);
function Parent() {
const [name, setName] = useState("John");
return (
<div>
<MyComponent name={name} />
<button onClick={() => setName("Jane")}>Change Name</button>
</div>
);
}
Refs: In React, refs (short for references) provide a way to access and interact with DOM elements or React components directly. Normally, in React, you interact with the UI through the state and props, but sometimes you need to perform operations on DOM elements (like focusing on an input field or measuring the size of an element). This is where refs come into play.
class MyComponent extends React.Component { constructor(props) { super(props); // Create a ref to store the DOM element this.inputRef = React.createRef(); } focusInput = () => { // Access the DOM node and focus it this.inputRef.current.focus(); }; render() { return ( <div> <input ref={this.inputRef} /> <button onClick={this.focusInput}>Focus the input</button> </div> ); } }
import React, { useRef } from "react"; const MyComponent = () => { const inputRef = useRef(); const focusInput = () => { // Access the DOM node and focus it inputRef.current.focus(); }; return ( <div> <input ref={inputRef} /> <button onClick={focusInput}>Focus the input</button> </div> ); };
Refs in React are a powerful feature for accessing and interacting with the DOM directly, without triggering re-renders. While they should be used sparingly and not as a substitute for state management, they provide essential functionality when you need to interact with the DOM imperatively or integrate with non-React libraries.
Forwarding refs in React is a technique used to pass a ref from a parent component to a child component. By default, refs are not passed through to child components when you pass them as props, but React provides a built-in feature called
React.forwardRef
to make this possible.const Button = React.forwardRef((props, ref) => { return <button ref={ref} {...props} />; }); function Parent() { const buttonRef = useRef(); const handleClick = () => { buttonRef.current.focus(); // Focus on the button }; return ( <div> <Button ref={buttonRef}>Click Me</Button> <button onClick={handleClick}>Focus on the Button</button> </div> ); }
Portals: Portals are used to create UI elements like modals, tooltips, or dropdowns that need to break out of their container but still interact with the React tree. To achieve this, we create a new root DOM element in the
index.js
file, similar to the main root DOM. All modals will be rendered inside this new root instead of breaking the main root DOM.// Create and another root node at index.html <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <div id="portal-root"></div> </body>
import React from "react"; import ReactDOM from "react-dom"; function Modal() { return ReactDOM.createPortal( // create the portals like this <div> <h2>This is a Modal</h2> </div>, document.getElementById("portal-root") ); } export default Modal;
Thanks for reading along.