Polymorphic React Components for Both the Client and the Server

Rate this content
Bookmark

Explore Server Components through the lens of reusable UI Component, where everything "depends" on the individual requirements of the use-case and individual application needs. Instead of fighting over 'server' vs 'client' - let's have the best of both worlds.

This talk has been presented at React Summit US 2024, check out the latest edition of this React Conference.

FAQ

The composition pattern allows mixing and matching server and client components within the rendering tree of a data table.

Kirill developed a server data table, which sends only HTML and interacts with the server, and a client component, which is interactive and works with browser APIs.

Rewriting the UI with Server Components was a bad idea because client components are still necessary for interactivity and some features.

BakaUI is a design system framework currently being built by Kirill.

Key considerations include avoiding code duplication, allowing customization by consumers, and accommodating changing requirements.

By not rendering their own children and separating their client logic into a client shell, components can be rendered as either client or server components.

A polymorphic data table is a single component that can be used both on the client and as a server component.

Kirill is building the next generation of the KendoUI React library full-time.

React Server Components promise a smaller bundle size, better performance, and improved data fetching.

View components assemble the actual slot, prepare its children, and ensure that components can be either client or server without affecting their children.

Kiril Peyanski
Kiril Peyanski
10 min
22 Nov, 2024

Comments

Sign in or register to post your comment.
Video Summary and Transcription
Hi, my name is Kirill and I have a little obsession with UI components. Let's talk React, specifically React 19 Server Components. I will show you how to build a polymorphic data table using server components. We explore mixing server and client components and applying the composition pattern. We discuss polymorphic components and separating client logic to render custom components without breaking client functionality. The component can be used in different environments, morphing into server or client components accordingly. This talk focuses on building a polymorphic component with minimal bundle size and access to both server and client APIs.

1. Introduction to React 19 Server Components

Short description:

Hi, my name is Kirill and I have a little obsession with UI components. Let's talk React, more specifically, the new edition of React 19, Server Components. When Server Components initially came out, they promised a smaller bundle size, better performance, and improved data fetching. Today, I want to show you how I built what I call a polymorphic data table, a single component which can be used on the client and as a server component.

Hi, my name is Kirill and I have a little obsession with UI components. In fact, I'm doing this full-time at Progress, building the next generation of the CanDo React library. During my free time, I love exploring the design system space, and currently I'm building a design system framework which I'm calling BackerUI.

But enough about me. Let's talk React, and more specifically, the new edition of React 19, Server Components, which if you ask me, should have been called simply React Components. But anyway, when Server Components initially came out, they promised a smaller bundle size, better performance, and improved data fetching, which led me to believe that I should rewrite all my user interface to use Server Components. This turned out to be a really bad idea, even Lee Robinson had to tweet that client components are actually fine. At some point, I even had a server button. It looked exactly like a regular button, but it was mostly useless because it didn't have a click event. I ended up keeping my client components.

But along the way, I realized I had a client and a server variant of some of my components. On paper, a data table could greatly benefit from being a server component, but I still needed to provide interactivity for implementing more dynamic dashboards or e-commerce shopping carts. Today, I want to show you how I built what I call a polymorphic data table, a single component which can be used to put on the client and as a server component. But before that, let's make sure that we are all visualizing the same thing when we think data table. A data table usually displays tabular data. It can have a header, a body, multiple rows with cells inside which shows formatted data. Cool. Now we're on the same page. But I still ended up with two really similar looking UI components.

One server data table, which sent only HTML to the client, had access to my file system and even a database instance. And one client component, which was interactive. I could edit, sort, and filter the data without a trip back to the server and had access to the browser APIs and the DOM. Usually, if I was building my personal blog posts, it would be perfectly fine to have two similar looking UI components with different purposes. However, if you are like me and are building a reusable UI library, being an open source one or something for other teams in your organization, there are a couple of things you should consider. First is code duplication. You probably do not want to maintain two separate code bases, which do almost the same thing, rendering a couple of rows with cells inside. Second is how consumers of your library would further modify to meet their requirements. A lot of applications have individual needs which may require a mix of server and client code, customizing all parts of your component along the way. And lastly, requirements change. They always do.

Read also

2. Mixing Server and Client Components

Short description:

Someone starting with the server component should be able to easily add interactivity later on without having to replace the whole component. Let's explore how the rendering tree of a data table would look like and see if we can apply the composition pattern there. Most of the rendering tree would end up not being able to use server components at all.

Someone starting with the server component should be able to easily add interactivity later on without having to replace the whole component. A specific pattern has emerged to help us mix and match server and client components. You have probably seen this diagram, which we refer to when speaking about the composition pattern.

Everything looks good on paper, but it is often applied on an application level. When we zoom into the component level, UI libraries are usually going full client mode, which diminishes the benefits of using server components. Let's explore for a bit how the rendering tree of a data table would look like and see if we can apply the composition pattern there. If you have tried implementing a data table before, you would quickly come to the realization that you need client code almost anywhere in the tree. Being for accessibility or adding a simple row selection feature, most of the rendering tree would end up not being able to use server components at all.

This is problematic because consumers of your data table might still want to keep some of the rendering on the server. But from the rules of server components, we know that while server components can render client components, the opposite is not true. There is, however, a way to achieve this by passing everything through the children pod prop, but we are going to explore this in a minute. Now, back to our data table.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Scaling Up with Remix and Micro Frontends
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Scaling Up with Remix and Micro Frontends
Top Content
This talk discusses the usage of Microfrontends in Remix and introduces the Tiny Frontend library. Kazoo, a used car buying platform, follows a domain-driven design approach and encountered issues with granular slicing. Tiny Frontend aims to solve the slicing problem and promotes type safety and compatibility of shared dependencies. The speaker demonstrates how Tiny Frontend works with server-side rendering and how Remix can consume and update components without redeploying the app. The talk also explores the usage of micro frontends and the future support for Webpack Module Federation in Remix.
Understanding React’s Fiber Architecture
React Advanced 2022React Advanced 2022
29 min
Understanding React’s Fiber Architecture
Top Content
This Talk explores React's internal jargon, specifically fiber, which is an internal unit of work for rendering and committing. Fibers facilitate efficient updates to elements and play a crucial role in the reconciliation process. The work loop, complete work, and commit phase are essential steps in the rendering process. Understanding React's internals can help with optimizing code and pull request reviews. React 18 introduces the work loop sync and async functions for concurrent features and prioritization. Fiber brings benefits like async rendering and the ability to discard work-in-progress trees, improving user experience.
Full Stack Components
Remix Conf Europe 2022Remix Conf Europe 2022
37 min
Full Stack Components
Top Content
RemixConf EU discussed full stack components and their benefits, such as marrying the backend and UI in the same file. The talk demonstrated the implementation of a combo box with search functionality using Remix and the Downshift library. It also highlighted the ease of creating resource routes in Remix and the importance of code organization and maintainability in full stack components. The speaker expressed gratitude towards the audience and discussed the future of Remix, including its acquisition by Shopify and the potential for collaboration with Hydrogen.
The Eternal Sunshine of the Zero Build Pipeline
React Finland 2021React Finland 2021
36 min
The Eternal Sunshine of the Zero Build Pipeline
For many years, we have migrated all our devtools to Node.js for the sake of simplicity: a common language (JS/TS), a large ecosystem (NPM), and a powerful engine. In the meantime, we moved a lot of computation tasks to the client-side thanks to PWA and JavaScript Hegemony.
So we made Webapps for years, developing with awesome reactive frameworks and bundling a lot of dependencies. We progressively moved from our simplicity to complex apps toolchains. We've become the new Java-like ecosystem. It sucks.
It's 2021, we've got a lot of new technologies to sustain our Users eXperience. It's time to have a break and rethink our tools rather than going faster and faster in the same direction. It's time to redesign the Developer eXperience. It's time for a bundle-free dev environment. It's time to embrace a new frontend building philosophy, still with our lovely JavaScript.
Introducing Snowpack, Vite, Astro, and other Bare Modules tools concepts!
Composition vs Configuration: How to Build Flexible, Resilient and Future-proof Components
React Summit 2022React Summit 2022
17 min
Composition vs Configuration: How to Build Flexible, Resilient and Future-proof Components
Top Content
Today's Talk discusses building flexible, resilient, and future-proof React components using composition and configuration approaches. The composition approach allows for flexibility without excessive conditional logic by using multiple components and passing props. The context API can be used for variant styling, allowing for appropriate styling and class specification. Adding variants and icons is made easy by consuming the variant context. The composition and configuration approaches can be combined for the best of both worlds.
Remix Architecture Patterns
Remix Conf Europe 2022Remix Conf Europe 2022
23 min
Remix Architecture Patterns
Top Content
This Talk introduces the Remix architecture patterns for web applications, with over 50% of participants using Remix professionally. The migration from single page applications to Remix involves step-by-step refactoring and offers flexibility in deployment options. Scalability can be achieved by distributing the database layer and implementing application caching. The backend for frontend pattern simplifies data fetching, and Remix provides real-time capabilities for collaborative features through WebSocket servers and Server-SendEvents.

Workshops on related topic

AI on Demand: Serverless AI
DevOps.js Conf 2024DevOps.js Conf 2024
163 min
AI on Demand: Serverless AI
Top Content
Featured WorkshopFree
Nathan Disidore
Nathan Disidore
In this workshop, we discuss the merits of serverless architecture and how it can be applied to the AI space. We'll explore options around building serverless RAG applications for a more lambda-esque approach to AI. Next, we'll get hands on and build a sample CRUD app that allows you to store information and query it using an LLM with Workers AI, Vectorize, D1, and Cloudflare Workers.
High-performance Next.js
React Summit 2022React Summit 2022
50 min
High-performance Next.js
Workshop
Michele Riva
Michele Riva
Next.js is a compelling framework that makes many tasks effortless by providing many out-of-the-box solutions. But as soon as our app needs to scale, it is essential to maintain high performance without compromising maintenance and server costs. In this workshop, we will see how to analyze Next.js performances, resources usage, how to scale it, and how to make the right decisions while writing the application architecture.