Portals, Suspense, Transitions, Forward Ref & HOC
ReactDOM.createPortal lets you render a modal or tooltip into document.body while keeping it in the same React component tree for events and state.
Portals — render outside the parent DOM tree
ReactDOM.createPortal lets you render a modal or tooltip into document.body while keeping it in the same React component tree for events and state.
Real-life example: A portal is a pop-up stall outside the main shop — separate location, still run by the same owner (your React app).
import { createPortal } from "react-dom";
function Modal({ open, children, onClose }) {
if (!open) return null;
return createPortal(
<div className="overlay" onClick={onClose}>
<div className="modal" onClick={(e) => e.stopPropagation()}>
{children}
</div>
</div>,
document.body
);
}Suspense — loading boundaries
Suspense shows a fallback UI while child components load data or lazy-loaded code. Pair with React.lazy for code splitting.
Real-life example: Suspense is a "Please wait" sign at a restaurant while the kitchen (lazy component) prepares your order.
import { Suspense, lazy } from "react";
const HeavyChart = lazy(() => import("./HeavyChart.jsx"));
function Dashboard() {
return (
<Suspense fallback={<p>Loading chart...</p>}>
<HeavyChart />
</Suspense>
);
}Transitions — useTransition
useTransition marks state updates as non-urgent so typing stays smooth while a heavy list re-filters.
Real-life example: useTransition is letting urgent guests (typing) through the door first while heavy luggage (big re-render) waits in the queue.
import { useState, useTransition } from "react";
function SearchList({ items }) {
const [query, setQuery] = useState("");
const [isPending, startTransition] = useTransition();
function handleChange(e) {
const value = e.target.value;
setQuery(value);
startTransition(() => {
// heavy filter update marked as transition
});
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <span>Updating...</span>}
</>
);
}Forward Ref — pass refs to child DOM nodes
forwardRef lets a parent get a ref to a child's DOM element — useful for focus, measurements, or third-party libraries.
Real-life example: forwardRef is like giving your manager a direct phone line to your desk — they reach you without going through the whole office chain.
import { forwardRef, useRef } from "react";
const FancyInput = forwardRef(function FancyInput(props, ref) {
return <input ref={ref} className="fancy" {...props} />;
});
function Form() {
const inputRef = useRef(null);
return (
<>
<FancyInput ref={inputRef} placeholder="Focus me" />
<button onClick={() => inputRef.current?.focus()}>Focus</button>
</>
);
}HOC — Higher-Order Components
A HOC is a function that takes a component and returns a new component with extra props or behavior. Hooks replaced many HOC use cases, but you will see withAuth(UserPanel) patterns in legacy code.
Real-life example: A HOC is a gift wrapper — same gift inside (component), extra ribbon and tag (added behavior) outside.
function withLoading(Wrapped) {
return function WithLoading(props) {
if (props.loading) return <p>Loading...</p>;
return <Wrapped {...props} />;
};
}
const UserListWithLoading = withLoading(UserList);