Like what we’re doing? Star us on GitHub!

Launch Week - Day 4

James Mikrut

James Mikrut headshot
Launch Week Day 4 - React Form ControlLaunch Week Day 4 - React Form Control

Day 4's launch spotlights a complete revamp for how React fields subscribe to form state in the admin UI. It unlocks a ton of new potential for your custom React components.

So, today's launch is pretty nerdy but super important.

Payload's admin UI has always been super fast, but we had to jump through some serious hoops to get there. The good React form libraries out there have to employ insane performance optimizations to make sure that, say, 1,000 fields at once can render and perform flawlessly within a given view.

Add in Payload's conditional logic, field-based localization, field-based access control, dynamic fields like Arrays and Blocks—and you've got a very demanding list of features that the form library needs to deliver.

Performance, in specific, is why lots of headless CMS place restrictions on how many fields can be rendered at once on a given view. And we don't like restrictions.

We first realized that we'd need to be especially conscious of form performance in 2020 with some real-world Payload projects like the My290 web app that's fully powered by Payload. That project stores hundreds of meta attributes for any given custom sign design, and they all need to be managed in a long, scrolling admin view. There were easily hundreds of fields rendered on one Edit page and we quickly realized the reason why lots of other headless CMS place restrictions on how many fields can be rendered in one view.

So, even before our beta launch, we put in some serious time into optimizing our Form component and its fields.

To rectify this, we built a system where each field would maintain its own value, independently of the form state, and then send up its value to the form every time it changed. This has been the way that Payload optimized its forms since late 2020.

You might say — just use uncontrolled inputs — and this sounds nice, but in practice, it's not ideal because of the above list of requirements. Many of our form components do not rely on native HTML inputs (or anything similar). Consider an Array field. The Array field needs to be aware of its children, how many rows it has, how to drag + drop rows, and when to tell the backend that it doesn't have any rows. Quickly, uncontrolled HTML inputs become unsustainable.

Our solution worked well, but it came with some fringe drawbacks. Each field knew when it changed its own value, but it wouldn't know if its value was changed by something else.

Custom UI field using dispatchFields form reducer

Before today, the number field would continue to maintain its old value and not re-render. Its form value would have indeed been updated, but the field, having maintained its own value in its own state, would not rerender. We did this because this way, we could greatly eliminate unnecessary form field rerenders and keep performance high, even with thousands of fields being rendered at once.

It's beautiful. Now our fields each use Redux-like selectors to subscribe to their own individual form state, and will only re-render when their own field state changes.

We no longer need to duplicate / debounce / etc. each field's own value locally, and fields instantly respond to any change in state—no matter if it was triggered within the component or outside of it. Our code has gotten simpler, significantly more performant, and much more expected.

What does this mean for me?

It means that you can now influence form state in your own custom components in an intensely more flexible and understandable way. You can build controls that dynamically influence form state from anywhere within your form and be sure that your state updates are reflected instantly within the affected fields.

It unlocks an endless amount of extremely performant functionality and opens up the door to building even more things on top of Payload's admin UI.

Best part? It's not a breaking change. You can use this new form state management immediately.

Like what we're doing? Give us a star on GitHub

We're trying to change the CMS status quo by delivering editors with a great experience, but first and foremost, giving developers a CMS that they don't absolutely despise working with. All of our new features are meant to be extensible and work simply and sanely.

Get up and running with one line

Getting started with Payload is easy—and free forever. Just fire up a new terminal window and run the following command:

npx create-payload-app