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 🛠 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); // ~/store/withStore.ts import {withStore as withStoreHoc} from "next-state-adapter"; export const withStore = withStoreHoc.withTypes<RootStore>(); 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> ); } 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> ); }; 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} />; } 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} />; } 🎯 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
Top comments (2)
cool :)
Informative and straight to the point