DEV Community

Elyor
Elyor

Posted on • Edited on

2 1

Efficient State Management in Next.js App Router with next-state-adapter

Managing state efficiently in a Next.js App Router environment can be challenging, especially when dealing with Server Components and Client Components. This is where next-state-adapter comes into play—providing a seamless solution for managing state across your Next.js application.

🚀 Why next-state-adapter?

next-state-adapter is a state management adapter specifically designed for Next.js App Router. It offers:

  • Seamless integration with Next.js (app/ directory)
  • Efficient server-side data handling for initial state hydration
  • Simplified state hydration in Client Components
  • Support for class components with an easy-to-use Higher-Order Component (HOC)
  • Works with various state management libraries like Mobx, Zustand, Jotai, Recoil, and others, giving you the flexibility to use your preferred state manager.

📦 Getting Started

First, install the package using npm or yarn:

npm install next-state-adapter
# or
yarn add next-state-adapter
Enter fullscreen mode Exit fullscreen mode

🛠 Setting Up next-state-adapter

1. Create the Root Store and Provider

Start by setting up the root store and necessary hooks for state management:

// ~/store/config.ts
'use client';

import {RootStore} from "@/store/root";
import {createProvider, useStore} from "next-state-adapter";

const makeStore = () => new RootStore();

export const useAppStore = useStore.withTypes<RootStore>();
export const useAppStoreHydration = useStoreHydration.withTypes<RootStore>();
export const StoreProvider = createProvider(makeStore);
Enter fullscreen mode Exit fullscreen mode
// ~/store/withStore.ts
import {withStore as withStoreHoc} from "next-state-adapter";

export const withStore = withStoreHoc.withTypes<RootStore>();
Enter fullscreen mode Exit fullscreen mode

2. Wrap Your Application with the Store Provider

Now, wrap your application in the StoreProvider component inside layout.tsx:

// ~/app/layout.tsx

export default function RootLayout({ children }: { children: React.ReactNode }) {
    return (
        <html lang="en">
            <body>
                <StoreProvider>
                    {children}
                </StoreProvider>
            </body>
        </html>
    );
}
Enter fullscreen mode Exit fullscreen mode

3. Use the Store in a Client Component

Let’s create a Todo List component that fetches initial data from the server and hydrates the client-side store:

// ~/todos/list.tsx
'use client';

const TodoList = ({ initialTodos }: { initialTodos: Todo[] }) => {
    const { todos } = useAppStoreHydration((store) => {
        store.todos.init(initialTodos);
    });

    return (
        <ul>
            {todos.todos.map((todo) => (
                <li key={todo.id}>{todo.title}</li>
            ))}
        </ul>
    );
};
Enter fullscreen mode Exit fullscreen mode

4. Use the Component in a Server Component

Now, fetch the initial state on the server and pass it to TodoList:

// ~/app/todos/page.tsx
export default async function Todos() {
    const initialTodos = await fetchTodos(); // Fetching initial data on server side

    return <TodoList initialTodos={initialTodos} />;
}
Enter fullscreen mode Exit fullscreen mode

5. Support for Class Components

If you're using class components, next-state-adapter provides an easy way to inject the store via HOC:

type Props = {
    store: RootStore;
    initialUsers: User[];
};

class Users extends Component<Props> {
    render() {
        const { store } = this.props;
        const users = store.users.users;

        return (
            <div>
                {users.map((user) => (
                    <div key={user.id}>{user.id}</div>
                ))}
            </div>
        );
    }
}

// Inject store and hydrate with initialUsers
typescript
export const UsersList = withStore(Users, (store, props) => {
    store.users.init(props.initialUsers);
});

// Use in a server component
export default async function UsersPage() {
    const initialUsers = await fetchUsers();
    return <UsersList initialUsers={initialUsers} />;
}
Enter fullscreen mode Exit fullscreen mode

🎯 Final Thoughts

The next-state-adapter simplifies state management in Next.js App Router applications by providing a structured, optimized. Whether you are working with functional components, class components, or server-side data hydration, this adapter ensures a smooth developer experience.

It also supports a wide range of state management libraries like Mobx, Zustand, Jotai, Recoil, and others, so you can integrate it with your preferred solution effortlessly.

Give it a try in your Next.js App Router project and experience a more efficient way to manage state!

🚀 Check out the official documentation: next-state-adapter docs

🚀 Link to npm: next-state-adapter npm

Hot sauce if you're wrong - web dev trivia for staff engineers

Hot sauce if you're wrong · web dev trivia for staff engineers (Chris vs Jeremy, Leet Heat S1.E4)

  • Shipping Fast: Test your knowledge of deployment strategies and techniques
  • Authentication: Prove you know your OAuth from your JWT
  • CSS: Demonstrate your styling expertise under pressure
  • Acronyms: Decode the alphabet soup of web development
  • Accessibility: Show your commitment to building for everyone

Contestants must answer rapid-fire questions across the full stack of modern web development. Get it right, earn points. Get it wrong? The spice level goes up!

Watch Video 🌶️🔥

Top comments (2)

Collapse
 
oqiljon_dadaxanov_2322ce5 profile image
Oqiljon Dadaxanov

cool :)

Collapse
 
azeek profile image
Azeek

Informative and straight to the point

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay