State management in Puck codebase.

In this article, we review state management in Puck codebase. We will look at:
Zustand store
Slices created
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:
https://github.com/puckeditor/puck/blob/main/packages/core/store/index.ts#L118
https://github.com/puckeditor/puck/blob/main/packages/core/store/slices/history.ts
https://zustand.docs.pmnd.rs/middlewares/subscribe-with-selector
https://github.com/puckeditor/puck/tree/main/packages/core/store/slices
https://github.com/puckeditor/puck/blob/main/packages/core/lib/use-parent.ts#L1
Subscribe to my newsletter
Read articles from Ramu Narasinga directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Ramu Narasinga
Ramu Narasinga
I study large open-source projects and create content about their codebase architecture and best practices, sharing it through articles, videos.