Home >Web Front-end >JS Tutorial >Managing application state in Puck

Managing application state in Puck

DDD
DDDOriginal
2025-01-14 22:35:45442browse

Puck is the open-source visual editor for React, empowering the next generation of page builders and no-code products. Give us a star on GitHub! ⭐️


Puck has been rapidly growing, and it’s been awesome to watch! ? Developers from all backgrounds are pushing the boundaries of what this open-source visual editor can do. But as more people dive into Puck, one question keeps coming up in our Discord community:

“How can I pass data or share state between components in Puck?”

In other words: how do you make one component react to changes in another? For example, you might create a DropZone component with a search input, so that any lists dropped inside it can read its value:

Managing application state in Puck

At first, Puck’s built-in magic might make you think it handles state in a unique way. But here’s the thing: Puck is just React—and so are the components you pass into it. That means that you can rely on any state library or tool you would normally use to manage and share data between components. For this article, I’ll keep it simple and teach you how to solve this problem by using Context.

Before we get started: I’ll assume you’ve got a basic understanding of Puck and how it works. If you’re new here, that’s totally fine—you’re welcome to follow along! But I’d recommend checking out the getting started guide first to get familiar with the basics

Project Setup

To make things easy, I’ve prepared a basic React project on GitHub with Puck pre-installed and ready to go. Clone and install it by running the following commands in your terminal:

git clone https://github.com/FedericoBonel/basic-puck-app
cd ./basic-puck-app
npm install

Already working on an existing project? No problem at all! You can simply install Puck as a dependency with NPM:

npm i @measured/puck --save

And if you’re using frameworks like Next.js or Remix, Puck offers official recipes to make the setup process seamless.

For this tutorial, I’ll assume you’ve cloned the GitHub repo to keep things straightforward. That said, the concepts and steps will apply to any setup—just update the file names as needed to fit your project’s structure.

Configuring Puck

With your project ready to go, the next step is to configure Puck. Open the src/App.jsx file and swap its contents with the code below. This will set up Puck with a basic config for dragging and dropping two components:

  • A Dashboard component that greets users and contains a DropZone for nesting other components
  • An ArticleList component that displays a list of articles inside the Dashboard
git clone https://github.com/FedericoBonel/basic-puck-app
cd ./basic-puck-app
npm install

Managing application state in Puck

Great! Your basic setup is now complete. Next, let’s dive into adding shared state to your editor.

Adding Context

React Context is the perfect solution for our problem because it offers a simple way to share and manage data across all your components—both inside and outside the editor. It creates a "global state" that you can access whenever needed, making it ideal for scenarios where you need to pull in data from outside Puck—like the selected theme or the logged-in user—or share data between Puck components.

In this guide, I’ll walk you through two common use cases for React Context within Puck:

  1. Accessing data stored outside Puck: We’ll begin by setting up a context containing a logged-in user’s data outside of the component, and then access it from within Puck components.
  2. Passing data to a nested component: Next, we’ll set up a search query context within the Dashboard. This will allow us to capture a user’s search query, store it in the context, and pass it down to the ArticleList component. The goal is to filter the list of articles based on the user’s query, demonstrating how to pass data between a parent and child Puck component.

Step 1: Define the Context outside Puck

Setting up context in Puck follows the same pattern as any React app. You create a Context provider to define and manage your shared state, wrap it around a parent component, and access or update the state wherever it's required in your app.

Start by creating a new Context for the user data. This Context will include both the user object and a function to update the user state.

npm i @measured/puck --save

Step 2: Create the Context Provider outside Puck

Next, create a UserProvider component that will wrap your Puck editor. This provider will manage the user state and make it available to all children.

For the sake of brevity, I’m using a dummy user and the setter function returned by useState.

// App.jsx
import { Puck, DropZone } from "@measured/puck";
import "@measured/puck/puck.css";

// The configs for your draggable components
// Ideally you would pull these out into their own files
const dashboardConfig = {
  render: () => {
    return (
      <div
       >



<p>Once you’ve updated the file, start the application in development mode, and navigate to http://localhost:5173 to verify everything is working as expected:<br>
</p>

<pre class="brush:php;toolbar:false">npm run dev

Step 3: Integrate the Provider with Puck

To integrate the provider with your Puck editor, simply wrap the editor with the UserProvider. You can put the UserProvider anywhere above the editor in your component tree (like in your index file), and it'll work just fine. Once you've done that, all your editor components will have access to the context!

git clone https://github.com/FedericoBonel/basic-puck-app
cd ./basic-puck-app
npm install

Step 4: Consume the Context in the Puck Components

Now you can access the UserContext in any of your Puck components. Following our use case example, let’s update the Dashboard component so that it displays a “welcome back” message for logged-in users and a “generic welcome” message for guests.

npm i @measured/puck --save

Step 7: Consume the Context from Puck components

Now, we’ll read the context in the components that are dropped inside the context provider. In our case, we’ll consume the context in the ArticleList component, which the user has nested inside the Dashboard via the DropZone. This allows the ArticleList to respond to changes in the search query and update accordingly.

// App.jsx
import { Puck, DropZone } from "@measured/puck";
import "@measured/puck/puck.css";

// The configs for your draggable components
// Ideally you would pull these out into their own files
const dashboardConfig = {
  render: () => {
    return (
      <div
       >



<p>Once you’ve updated the file, start the application in development mode, and navigate to http://localhost:5173 to verify everything is working as expected:<br>
</p>

<pre class="brush:php;toolbar:false">npm run dev

If you now head into the editor, drag a Dashboard component onto the canvas, drop an ArticleList inside it, and modify the initialQuery field, you’ll see the list dynamically filter the articles based on the query. ?

Managing application state in Puck

You could even expand this setup by having multiple list components with different content reuse the same query context.

? And that’s it! You now have shared state between nested Puck components. ?

Pros & Cons of using React Context

✅ Pros:

  • Provides a robust solution for sharing state across components, both inside and outside Puck
  • Integrates seamlessly with existing React patterns and components
  • Can handle complex logic and state
  • Zero external dependencies as React Context comes with React

❌ Cons:

  • Performance can degrade if you frequently update state at the top of a large component tree, as every subscriber needs to re-render
  • When managing multiple context providers, things can become harder to debug

Taking it further

There are a bunch of ways in which you can improve managing shared state in Puck depending on the complexity of your editor:

  • Optimize context usage - If you notice performance issues or unnecessary re-renders, consider splitting your context into smaller, more focused contexts. This allows components to subscribe only to the parts of the state they need, minimizing re-renders.
  • Incorporate state libraries - If you have multiple shared states and more complex logic, you could move beyond React Context and use your favorite state library. Whether it’s Redux, Zustand, or another library your project is already using, these can simplify managing complex state and improve rendering performance.
  • Leverage server-side state - If your application relies heavily on data fetched from a server, consider using a library like TanStack Query or SWR. These libraries manage caching, re-fetching, and synchronization for you, reducing the need for complex shared client-side state.

Your Turn to Build Smarter with Puck ?

Taking shared state management in Puck to the next level unlocks a world of possibilities for building dynamic, reactive page builders. I’m excited to see the unique and powerful apps you’ll build using these strategies.

So, if this article has inspired you to build something, you have a question about Puck or you want to contribute, here’s how you can get involved:

  • ? Star Puck on GitHub to show your support and inspire others to explore.
  • ? Join our Discord community to connect, learn, and collaborate.
  • ? Follow us on X and Bluesky for sneak peeks, updates, and tips.
  • ? Explore the documentation for advanced techniques to supercharge your builds.

The future of Puck—and no-code innovation—is in your hands. Start building today, and let’s redefine what’s possible together! ?

The above is the detailed content of Managing application state in Puck. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn