React Router 7 : some thoughts

React Router 7 is transforming the way developers build web applications with React. Far more than a routing library, it has grown into a powerful framework for developing robust, data-driven apps featuring advanced navigation, server-side rendering (SSR), loaders, actions, and more. Whether you’re just starting or updating legacy projects, understanding React Router 7’s features will supercharge your development workflow.

Why React Router 7 is a Game Changer

React Router 7 introduces:

  • Nested Routing: Simplifies complex UIs with component-based layouts.
  • Data Loaders & Actions: Provides declarative ways to fetch data and manage forms.
  • Rendering Flexibility: Supports SPA, SSR, SSG, and hybrid workflows.
  • Pending & Optimistic UI Support: Handles async UI states seamlessly.
  • Modern Navigation APIs: Easier redirections and programmatic routing.

These features enable you to build sophisticated apps that scale from simple sites to full-stack, production-grade platforms.

Getting Started: Setting Up a React Router 7 Project

Start by initializing your project with the official template, ensuring all the latest dependencies and folder structures are in place:

npx create-react-router@latest my-react-router-app
cd my-react-router-app
npm install
npm run dev

This scaffolds a modern, best-practice project ready for advanced routing.

Core Concepts and Practical Examples

1. Basic Routing

Start by wrapping your app with <BrowserRouter>, the root provider for route management:

import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

createRoot(document.getElementById("root")!).render(
<BrowserRouter>
<App />
</BrowserRouter>
);

Define your application’s routes with <Routes> and <Route> components:

import { Routes, Route } from "react-router-dom";
import Home from './pages/Home';
import About from './pages/About';

function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}

2. Nested Routing and Layouts

Structure complex interfaces by nesting routes and harnessing shared layouts via the <Outlet /> component. For example, a dashboard could have shared side navigation with nested child routes for different sections.

3. Data Loaders

React Router 7’s loaders let you fetch route-specific data before rendering components, enhancing user experience and enabling better SSR and SSG strategies. Instead of fetching data in components, use loaders at the route level for cleaner and more predictable data flows.

4. Form Actions

Forms are now first-class citizens. Attach actions directly to routes to handle server mutations or form submissions declaratively. This empowers optimistic updates and simplifies traditional state management.

5. Rendering Strategies

React Router 7 is built with server-side rendering and static site generation in mind. Choose your data fetching and rendering approach per route for maximum flexibility—mix-and-match SSR, SSG, and SPA pages in a single app.

6. Pending and Optimistic UI States

Built-in support enables you to seamlessly show loading indicators while data is being fetched (pending) or immediately update the UI in response to user actions (optimistic), dramatically improving user experience.

7. Programmatic Navigation

Leverage useNavigate hook or <Navigate /> component for imperative navigation or redirect scenarios, essential for flows like authentication or user onboarding.

Recommended Learning Path

  1. Project setup and routing basics
  2. Working with loaders (data fetching)
  3. Handling forms using actions
  4. Navigation and redirects
  5. Choosing appropriate rendering strategies
  6. Optimistic UI and loading indicators
  7. Testing routes, loaders, and actions

By progressing in this order, you’ll build a solid understanding and comfortably wield the full power of React Router 7.

Final Thoughts

React Router 7 positions itself as a cornerstone for modern React apps—powerful, declarative, and flexible. As the boundaries between frontend and backend blur, mastering its advanced routing, data-loading, and rendering techniques is essential for any React developer aiming to build future-proof, data-rich applications.

Jump in, experiment with loaders and actions, and let React Router 7 elevate your React projects.

Happy coding!

Why Use Context in a Next.js App?

Next.js, with its rich feature set and server-side rendering capabilities, is the darling of modern web development. But as your Next.js app grows, managing state across components can become tricky. This is where the Context API steps in as your superhero. Let’s explore why using Context in a Next.js app is a smart choice and how it can make your developer life easier—and your app better!


1. The Problem: Prop Drilling Galore

Imagine you’re building a dashboard app. You need user data to show the user’s name in the header, their preferences in a settings panel, and their activity log on a sidebar. Without Context, you’ll find yourself passing this data through multiple layers of components, even if some intermediate components don’t care about it.

This practice, known as prop drilling, quickly turns your clean code into a tangled mess. The more deeply nested your components are, the messier it gets. That’s where the Context API comes to the rescue.


2. The Solution: Centralized State Management with Context

The Context API lets you create a global state that any component in your app can access, no matter how deeply nested. Instead of juggling props like a circus performer, you create a UserContext (or any context you need), wrap your app with a provider, and make the data available anywhere with a simple hook like useContext.

Here’s a quick example:

import { createContext, useContext, useState } from 'react';

// Create Context
const UserContext = createContext();

// Provider Component
export function UserProvider({ children }) {
  const [user, setUser] = useState(null);
  return (
    <UserContext.Provider value={{ user, setUser }}>
      {children}
    </UserContext.Provider>
  );
}

// Custom Hook
export function useUser() {
  return useContext(UserContext);
}

// In _app.js
import { UserProvider } from '../contexts/UserContext';

export default function App({ Component, pageProps }) {
  return (
    <UserProvider>
      <Component {...pageProps} />
    </UserProvider>
  );
}

Now, any component can access the user state without worrying about prop drilling. Clean and efficient!


3. Server-Side Rendering (SSR) Made Easy

Next.js shines with SSR and static site generation (SSG). With Context, you can seamlessly manage and share server-fetched data across your app. For instance, you can populate your context with user session data fetched via getServerSideProps or getInitialProps.

export async function getServerSideProps(context) {
  const user = await fetchUserFromSession(context.req);
  return {
    props: {
      initialUser: user,
    },
  };
}

function MyPage({ initialUser }) {
  const { setUser } = useUser();

  useEffect(() => {
    setUser(initialUser);
  }, [initialUser]);

  return <Dashboard />;
}

This pattern ensures data consistency and avoids the need for redundant API calls.


4. Perfect for Theming

Want to toggle between light and dark modes in your app? The Context API makes it ridiculously easy. Create a ThemeContext, store your current theme, and let your components consume it. Bonus: Combine it with Tailwind CSS for a dynamic theme switcher.


5. When NOT to Use Context

While Context is powerful, it’s not a silver bullet. For apps with very complex state management needs (like intricate forms or deeply interconnected states), consider state management libraries like Redux or Zustand. Context works best for lightweight, app-wide states.


In Conclusion

Using Context in your Next.js app isn’t just about avoiding prop drilling. It’s about writing cleaner, more maintainable code. It’s about making SSR a breeze. It’s about enabling features like theming without breaking a sweat. In short, it’s about building a better developer experience and a better app. So, next time you’re tempted to pass props through a dozen components, give Context a try—your future self will thank you!

Happy Coding!