Clean β’ Professional
CRA only renders on client β slower first load & poor SEO (search engines see empty HTML).
Next.js can pre-render pages on server (SSR, SSG, ISR). This gives:
Example:
// Next.js SSR example
export async function getServerSideProps() {
const products = await fetch("<https://api.example.com/products>").then(r => r.json());
return { props: { products } };
}
export default function Products({ products }) {
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
SSR (Server-Side Rendering): HTML is generated on every request.
Example β Live stock price page.
SSG (Static Site Generation): HTML is generated at build time (fast, cached).
Example β Blog posts.
ISR (Incremental Static Regeneration): HTML is cached and refreshed after some seconds.
Example β Product catalog updated every 60s.
export async function getStaticProps() {
const data = await fetchAPI();
return { props: { data }, revalidate: 60 }; // refresh after 60s
}
Next.js:
next-auth (popular).Β
Example:
// React Router private route example
function PrivateRoute({ children }) {
const isAuth = localStorage.getItem("token");
return isAuth ? children : <Navigate to="/login" />;
}
Dynamic import = Load a component only when needed β smaller initial bundle.
Example:
import dynamic from "next/dynamic";
const Chart = dynamic(() => import("./Chart")); // loaded only when used
Server-side (SSR): Fetch data on server before sending page.
export async function getServerSideProps() {
const data = await fetch("api.com");
return { props: { data } };
}
useEffect after page loads.function Page() {
const [data, setData] = useState([]);
useEffect(() => { fetch("api.com").then(r=>r.json()).then(setData); }, []);
}
componentDidCatch method.Example:
class ErrorBoundary extends React.Component {
state = { hasError: false };
componentDidCatch() { this.setState({ hasError: true }); }
render() { return this.state.hasError ? <h1>Something went wrong</h1> : this.props.children; }
}
findBy queries in React Testing Library (RTL).Example:
test("loads data", async () => {
render(<UserList />);
expect(await screen.findByText("John")).toBeInTheDocument();
});
Just test component behavior, not hook internals.
Trigger state changes and check UI.
Example:
test("counter increments", () => {
render(<Counter />);
fireEvent.click(screen.getByText("Increment"));
expect(screen.getByText("Count: 1")).toBeInTheDocument();
});
π Shallow = fast, Full = realistic.
Example:
// Shallow rendering with Enzyme
const wrapper = shallow(<MyComponent />);
React.memo, useMemo, useCallback where needed.Example:
const Child = React.memo(({ value }) => <div>{value}</div>);
React Fiber assigns lanes (priority levels) to updates.
Example: User typing (high priority) > Background fetch (low priority).
Helps React decide what to render first.
next/image).Example:
import Image from "next/image";
<Image src="/banner.png" width={500} height={300} priority />
Hydration = faster, used in SSR.
Example:
export async function getStaticProps() {
const posts = await fetch("...").then(r => r.json());
return { props: { posts }, revalidate: 30 }; // rebuild every 30s
}
Pros: Smaller bundle, better performance.
Cons: No hooks (useState, useEffect), limited interactivity.
Show fallback UI while waiting for data.
Makes app feel responsive.
Example:
<Suspense fallback={<Spinner />}>
<Profile />
</Suspense>
startTransition tells React that some updates are low priority.
UI stays responsive while background work happens.
Example:
import { startTransition } from "react";
startTransition(() => setSearch(query));
useEffect.Example:
useEffect(() => {
const id = setInterval(doWork, 1000);
return () => clearInterval(id); // cleanup
}, []);
Example:
const LazyComp = React.lazy(() => import("./HeavyComp"));
Example:
const Map = dynamic(() => import("../components/Map"), { ssr: false });
dangerouslySetInnerHTML carefully.Content-Security-Policy headers.Example:
<div>{userInput}</div> {/* safe */}
<div dangerouslySetInnerHTML={{ __html: trustedHTML }} /> {/* only trusted */}
Example:
import * as Sentry from "@sentry/react";
Sentry.init({ dsn: "your-dsn" });
workbox or CRA PWA template.Example (CRA PWA service worker):
// service-worker.js
self.addEventListener("fetch", e => {
e.respondWith(caches.match(e.request).then(res => res || fetch(e.request)));
});
unstable_batchedUpdates).Example:
import { FixedSizeList } from "react-window";
<FixedSizeList height={400} width={300} itemSize={35} itemCount={1000}
children={({index,style}) => <div style={style}>Row {index}</div>} />
Example (feature-based folder structure):
/src
/features
/auth
/dashboard
/profile
/shared
/components
/hooks
Β