0.0.3 • Published 4 months ago

next-state-adapter v0.0.3

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

next-state-adapter: is a state management adapter for Next.js App Router

next-state-adapter is state management adapter for Next.js App Router, enabling efficient state management in Server Components and Client Components.

For more detailed documentation, visit the official docs.

✨ Features

  • Works seamlessly with Next.js App Router (app/ directory)
  • Supports initial data placement in the server-side store
  • Ensures reactivity and performance optimizations
  • Simplifies state hydration and server-side stores

🚀 Quick Start

Install the package using npm or yarn:

npm install next-state-adapter
# or
yarn add next-state-adapter

📖 Usage

1. Configure root store, store provider, typed hook and withStore hoc

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

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

const makeStore = () => {
    return new RootStore()
}

export const useAppStore = useStore.withTypes<RootStore>();

// Hook for hydrating the client store with server data.
export const useAppStoreHydration = useStoreHydration.withTypes<RootStore>()

export const StoreProvider = createProvider(makeStore)

// if you need support class components, create HOC withStore (Don't write 'use client' in this file)
// ~/store/withStore.ts
export const withStore = withStoreHoc.withTypes<RootStore>()

2. Wrap your components to StoreProvider

// ~/app/layout.tsx

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

3. Create your component with store, hydrate with server data (example with Mobx, you can use any).

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

const TodoList = observer(({initialTodos}: { initialTodos: Todo[] }) => {
    const {todos} = useAppStoreHydration((store) => {
        // hydrate the client store with the server data
        store.todos.init(initialTodos)
    })

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

TodoList.displayName = 'Todos';

4. Use component on server component

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

    return (
        <>
            <TodoList initialTodos={initialTodos} />
        </>
    );
}

5. Using class components

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

class Users extends Component<Props, {}> {
    constructor(props) {
        super(props);
    }

    render () {
        const { store } = this.props;
        const users = store.users.users

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

// withStore will pass store to component as props
export const UsersList = withStore(Users, (store, props) => {
    const {initialUsers} = props
    store.users.init(initialUsers)
})

// server component
export default async function UsersPage() {
    const initialUsers = await fetchUsers()
    return (
        <UsersList initialUsers={initialUsers} />
    )
}
0.0.3

4 months ago

0.0.2

4 months ago

0.0.1

4 months ago