Blog
State management in Puck codebase.

State management in Puck codebase.

In this article, we review state management in Puck codebase. We will look at:

  1. Zustand store

  2. Slices created

  3. Context API used

Zustand store

Puck uses to Zustand to manage its state. You will find the store folder in puck/packages/core/store/index.ts.

The following is the signatore of createAppStore:

export const createAppStore = (initialAppStore?: Partial<AppStore>) =>
  create<AppStore>()(
    subscribeWithSelector((set, get) => ({

This is found to be using subscribeWithSelector function.

Slices created

You will find slices defined in puck/packages/core/store/slices folder. At the time of writing this article, Puck has the slices shown in the following image.

And these slices are defined in the store/index.ts as shown below:

import { createHistorySlice, type HistorySlice } from "./slices/history";
import { createNodesSlice, type NodesSlice } from "./slices/nodes";
import {
  createPermissionsSlice,
  type PermissionsSlice,
} from "./slices/permissions";
import { createFieldsSlice, type FieldsSlice } from "./slices/fields";
...
fields: createFieldsSlice(set, get),
history: createHistorySlice(set, get),
nodes: createNodesSlice(set, get),
permissions: createPermissionsSlice(set, get),

Context API used

At the end of store/index.ts, you will find the following code:

export const appStoreContext = createContext(createAppStore());

export function useAppStore<T>(selector: (state: AppStore) => T) {
  const context = useContext(appStoreContext);

  return useStore(context, selector);
}

export function useAppStoreApi() {
  return useContext(appStoreContext);
}

A context is created using createAppStore function and this context is used in other parts of code.

Following is an example found in puck/packages/core/lib/use-parent.ts

import { useAppStore, useAppStoreApi } from "../store";

export const useParent = () => {
  const appStore = useAppStoreApi();

  const selectedItem = appStore.getState().selectedItem;
  const parent = useAppStore((s) => {
    const node = s.state.indexes.nodes[selectedItem?.props.id];
    return node?.parentId ? s.state.indexes.nodes[node.parentId] : null;
  });

  return parent?.data ?? null;
};

About me:

Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.

Email: ramu.narasinga@gmail.com

Want to learn from open-source? Solve challenges inspired by open-source projects.

References:

  1. https://github.com/puckeditor/puck/blob/main/packages/core/store/index.ts#L118

  2. https://github.com/puckeditor/puck/blob/main/packages/core/store/slices/history.ts

  3. https://zustand.docs.pmnd.rs/middlewares/subscribe-with-selector

  4. https://github.com/puckeditor/puck/tree/main/packages/core/store/slices

  5. https://github.com/puckeditor/puck/blob/main/packages/core/lib/use-parent.ts#L1