Rsc Nextjs Server Rendering and Forms Management

Author

Reads 1.2K

HTML and CSS code on a computer monitor, highlighting web development and programming.
Credit: pexels.com, HTML and CSS code on a computer monitor, highlighting web development and programming.

Server rendering is a key feature of Next.js, and it's made even more powerful with RSC. With RSC, server rendering is enabled by default, which means that every page in your Next.js app is rendered on the server.

This approach provides a number of benefits, including improved SEO and faster page loads. RSC also allows for more efficient use of client-side resources, which can be a major advantage for complex applications.

One of the most significant advantages of RSC is its ability to handle forms more efficiently. With traditional client-side rendering, forms can be slow to load and may not work as expected. RSC, on the other hand, can render forms on the server, which makes them much faster and more reliable.

App Configuration

To configure your app, you'll need to wrap your root app page in the trpc.withTRPC HOC, similar to what's shown in the example.

You can customize the flow of data between the tRPC client and server by using the config-argument function. This function returns an object that configures the tRPC and React Query clients, and it can contain properties like links, queryClientConfig, queryClient, transformer, and abortOnUnmount.

Credit: youtube.com, Next 14 + React Query COMBO with Server Actions and RSC

Here are the required and optional properties you can include in the config-argument function:

  • Required:
  • links to customize the flow of data between tRPC Client and the tRPC Server.
  • Optional:
  • queryClientConfig: a configuration object for the React Query QueryClient used internally by the tRPC React hooks.
  • queryClient: a React Query QueryClient instance.
  • transformer: a transformer applied to outgoing payloads.
  • abortOnUnmount: determines if in-flight requests will be cancelled on component unmount.

Requirements

To set up an app configuration, you'll need to meet some basic requirements. You should have a basic understanding of JavaScript, React, and Next.js.

You'll also need to ensure you're running the correct versions of Node.js and Storyblok. Node.js LTS version is a must-have.

To give you a better idea, here are the specific versions used in the project:

Keep in mind that these versions may be slightly behind the latest ones.

Connecting to Storyblok

Connecting to Storyblok is a crucial step in setting up your Next.js app. To do this, you'll need to install the official React SDK, which allows you to interact with the Storyblok API and enables real-time editing experience.

The Storyblok SDK has a special module for App Router, and you should always import from @storyblok/react/rsc while using Server Components.

To initialize Storyblok in your Next.js project, go to the layout.js file inside the app directory and add the storyblokInit function. This function will take care of two things: initializing the connection with Storyblok and providing an API client that you can use to retrieve content from the platform.

Credit: youtube.com, Apps Directory - Storyblok Walkthrough

You can retrieve your Preview token from your Space Settings under Access Tokens in the Storyblok app. Add the token as the accessToken directly or from a .env file.

If you want to use an environment variable, you should follow the official Next.js tutorial and add the env config storyblokApiToken: process.env.STORYBLOK_API_TOKEN to your next.config.js file.

Here's a summary of the steps to connect to Storyblok:

  • Install the official React SDK.
  • Initialize Storyblok in your layout.js file using the storyblokInit function.
  • Retrieve your Preview token from your Space Settings and add it to your .env file or use an environment variable.

By following these steps, you'll be able to connect to Storyblok and enable the Visual Editor experience in your Next.js app.

Configure App Tsx

To configure your app, you need to wrap your root app page in the trpc.withTRPC HOC. This is done by adding the following code to your _app.tsx file.

You'll want to wrap your root app page in the trpc.withTRPC HOC, similar to this:

You can customize the flow of data between tRPC Client and the tRPC Server by using the config-argument function. This function has a ctx input that gives you access to the Next.js req object, among other things.

Credit: youtube.com, Azure App Configuration Tutorial

Here are the properties you can include in the config-argument function:

  • links: to customize the flow of data between tRPC Client and the tRPC Server.
  • queryClientConfig: a configuration object for the React Query QueryClient used internally by the tRPC React hooks.
  • queryClient: a React Query QueryClient instance.
  • transformer: a transformer applied to outgoing payloads.
  • abortOnUnmount: determines if in-flight requests will be cancelled on component unmount.

The config-argument function is optional, but it provides a lot of flexibility when it comes to customizing your app's behavior.

React and Forms

In Next.js, you can create forms using React Server Components (RSC) and Server Actions. This approach enables you to perform data fetching on the server and use server actions to handle form submissions.

Server actions receive the FormData object of the form as an argument, allowing you to access the form data and perform actions such as creating a new message.

With React's useFormState and useFormStatus hooks, you can create forms without using a library like Formik or React Hook Form, and you can keep form field elements uncontrolled.

Live Editing

Live Editing is a powerful feature that lets you see real-time updates as you work on your project. This is especially useful when you're creating a new space from scratch, as Storyblok automatically creates four default components for you.

Credit: youtube.com, React Hook Form - Complete Tutorial (with Zod)

To take full advantage of Live Editing, you need to load the components on the client side, which involves creating a wrapper to reinitialize the Storyblok connection. This wrapper is called StoryblokProvider.js.

Inside the StoryblokProvider.js file, you'll find code that tags the component as client-side and reinitializes the Storyblok connection. This is necessary because the initialization inside the layout file helps fetch data from Storyblok.

To use this wrapper in the layout, you need to add the StoryblokProvider.js file to your layout.js file. This will enable Live Editing, allowing you to see real-time updates as you work on your project.

Full React

Full React is all about utilizing server components to their full potential. This approach keeps everything server-side, which has a limitation - real-time editing won't work if all components are rendered on the server.

You can clone or explore the full-server-side branch of Next.js 13 Storyblok Bolierplate to get started. The StoryblokBridgeLoader loads the bridge on the client behind the scenes, allowing you to click components in the Visual Editor and register events to reload the editor when you click Save or Publish.

Credit: youtube.com, Learn React JS - Full Beginner’s Tutorial (2024) & Practice Projects

One key thing to note is that you can pass bridge options through a prop named options. This is useful for customizing the bridge behavior to suit your needs.

To render dynamic components in the Next.js app, you'll need to use the Storyblok API to receive the page in JSON format. This is what we want to accomplish in our Next app, and it's something we've already done in a previous step.

Here's a summary of the steps to create components in the Next.js app:

  • Create the counterparts of the four components discussed above in your Next.js app
  • Use storyblokEditable with any component to make them clickable in the Storyblok Visual Editor and editable in real-time
  • Use the StoryblokComponent feature to load the right content in Next.js
  • Configure the components identified by StoryblokComponent and link them to their representation in the Storyblok space

By following these steps, you'll be able to render dynamic components in your Next.js app and enable live editing.

Resetting Forms in Next

In Next.js, you can reset a form after a successful submission using the formState and timestamp. To do this, you'll need to create a custom hook that takes the form state and timestamp as arguments.

You can use React's useRef Hook to attach a ref to the form, but this will break progressive enhancement when the compiled application is used without JavaScript. Fortunately, you have everything in place to reset the form using the formState and timestamp.

To create a custom hook, you'll need to import the FormState from the previously created file, as mentioned in Example 2. This knowledge should not be in the action file anymore.

Nesting

Credit: youtube.com, React Hook Form Tutorial - 13 - Nested Objects

Server Components can be nested, allowing them to exist on multiple levels in the React tree. This makes it possible to prefetch data closer to where it's actually used, rather than only at the top of the application.

You can use Server Components to render other Server Components, creating a hierarchical structure. For example, a Server Component might render another Server Component.

It's perfectly fine to use multiple HydrationBoundaries and create and dehydrate multiple queryClient instances for prefetching. This allows for more flexibility in how you structure your application.

Server-side waterfalls can occur when using nested Server Components, especially if the server latency to the data is high. This is because the server will wait for the inner component to finish rendering before rendering the outer component.

Next.js can help mitigate this issue by prefetching data in parallel routes, which can flatten the waterfall effect. This is especially useful when using nested Server Components.

Actions and Hooks

Credit: youtube.com, React Hook Form & React 19 Form Actions, The Right Way

To use Server Actions in Next.js, you can create a new component as a provider for toast messages, and then use the imported toast function to show a general message in the form component. This allows you to display errors per form field and a general message to the user.

You can use React's useEffect Hook to show the toast message, but be aware that the message will only show up once due to the timestamp. To fix this, you can extract the useEffect Hook into a custom hook and add the timestamp to the dependency array.

For progressive enhancement, you can use React's useRef Hook to reset the form after a successful submission, but this will break if the application is used without JavaScript. Instead, you can use the formState and timestamp to reset the form, making it work without JavaScript in the browser.

Actions

Actions are a fundamental part of Next.js, and they're especially useful when combined with React Server Components. You can create, read, update, and delete (CRUD) operations using Server Actions.

Credit: youtube.com, Action Hooks

To display errors per form field, you can use Zod's schema parsing and derive the fieldErrors property of the form state. This is exactly what we did in our form component.

Server Actions can be used to execute code on the server, which is a game-changer for handling database operations. By using Server Actions, you can keep your client-side code clean and focused on rendering the UI.

To show a general message to the user, we used a toast message in our form component. We installed a popular library to help with this, and created a new component called Provider to render the toast messages.

The Provider component is used in the root layout of the application and is responsible for rendering the toast messages. This is a great way to keep your code organized and reusable.

To update the toast message to show up for each form submission, we extracted the useEffect Hook into its own custom hook. We added the timestamp to the dependency array and checked whether the timestamp changed compared to the previous timestamp.

By using the new custom hook in our form component, we can provide it with the form state, the general message, the status for the style, and the timestamp for the dependency array. This ensures that the toast message shows up for each form submission.

Create Trpc Hooks

Credit: youtube.com, Fetching Data Doesn't Get Better Than This

To create tRPC hooks, you use the createTRPCNext function. This function creates a set of strongly-typed hooks from your API's type signature.

The createTRPCNext function is used to generate hooks that are tailored to your API's specific needs. It's a powerful tool that helps you build robust and scalable applications.

One thing to keep in mind is that createTRPCNext does not work with the tRPC-v9 interop mode. If you're migrating from v9 using interop, you should continue using the old way of initializing tRPC.

This means you'll need to choose between using the createTRPCNext function or the older method of initializing tRPC, depending on your specific use case and requirements.

Forms and Validation

Forms in Next.js with server actions and server components are different from client-side/SPA React, as we don't allocate shared state between components.

We can create forms without using libraries like Formik or React Hook Form by using the useFormState and useFormStatus hooks provided by React. These hooks allow us to create forms without using React's useState hook for the form state, and all form field elements can stay uncontrolled.

Server actions passed to the form action attribute receive the FormData object of the form, which encapsulates all the data of the form. We can use this object to get the value of the text field and add a new message to the messages array.

State of Forms

Credit: youtube.com, This is why useFormState and useFormStatus are important

Forms in Next.js are getting a major overhaul, with a focus on simplicity and progressive enhancement. Server actions and server components are changing the way we think about forms, making it possible to render forms on the server and have a great user experience with JavaScript enabled.

Server actions passed to the form action attribute receive the FormData object of the form as the first argument, which encapsulates all the data of the form. This allows us to get the value of the text field to add a new message to the messages array.

Using React's useFormState and useFormStatus hooks is a great way to get a better understanding of the new paradigm. These hooks provide a simple way to manage form state and status without the need for a form library like Formik or React Hook Form.

Independent from the form topic at hand, notice how this is already different from client-side/SPA React, because we do not allocate shared state between both components in this parent component nor will we in the future. This is a key difference between server-side and client-side rendering.

Credit: youtube.com, STOP using useState for React forms (there's an alternative method)

We can already create a message and see it in the list, but to actually see the newly created message in the list of messages we still need to reload/refresh the browser. What's missing is revalidating Next's full route cache.

To add more complexity to our form, we need to jump through a few hoops, including learning more about the new hooks, server actions, and React server components. At this point, you are likely confronted with the following error:

Revalidate Path After Submission

You can revalidate a page's path after a form submission without reloading the page, thanks to Next's revalidatePath function.

This function is used to revalidate the page's path, which instructs Next to take care of the cache for this page and render the revalidated data.

Calling revalidatePath after mutating the data in memory ensures that the Full Route Cache is updated, eliminating the need to reload the browser.

By using revalidatePath, you can see the new message in the list (and all other revalidated data) without reloading the page.

Data Management

Credit: youtube.com, This Makes State Management so Much Easier

Data Management with RSC and Next.js is a delicate balance between Server and Client Components. You can't just render data from Server Components on the client without considering data ownership and revalidation.

To avoid issues with data revalidation, it's essential to think about data ownership. This means that Server Components should not own data that can be revalidated on the client. React Query has no idea how to revalidate Server Components, so if it refetches the data on the client, the data will end up out of sync.

If you set staleTime: Infinity, React Query will never revalidate, but this is probably not what you want if you're using React Query in the first place. This approach is more suitable for apps that don't need data revalidation.

Here are some scenarios where pairing React Query with Server Components makes sense:

  • You have an app using React Query and want to migrate to Server Components without rewriting all the data fetching
  • You want a familiar programming paradigm, but want to still sprinkle in the benefits of Server Components where it makes most sense
  • You have some use case that React Query covers, but that your framework of choice does not cover

Frequently Asked Questions

What is RSC in React?

React Server Components (RSC) is a new approach to web development that enables a two-phase UI build process, improving performance and addressing client-only architecture challenges. This innovative technology streamlines web development, making it easier to create fast and efficient user interfaces.

What is the difference between RSC and SSR?

RSC and SSR differ in their focus: RSC prioritizes performance for apps with complex rendering, while SSR optimizes for SEO and fast content delivery. Choose between them based on your app's specific needs.

What is RSC payload?

The RSC Payload is a compact binary representation of the React Server Components tree, containing the rendered result of Server Components. It's used by React to update the browser's DOM efficiently.

Does Next.js have Csrf protection?

Next.js has built-in protection against CSRF attacks, but it can be further enhanced with the next-csrf package. This additional layer ensures that only authenticated users can make requests, significantly reducing the risk of unauthorized actions.

Glen Hackett

Writer

Glen Hackett is a skilled writer with a passion for crafting informative and engaging content. With a keen eye for detail and a knack for breaking down complex topics, Glen has established himself as a trusted voice in the tech industry. His writing expertise spans a range of subjects, including Azure Certifications, where he has developed a comprehensive understanding of the platform and its various applications.

Love What You Read? Stay Updated!

Join our community for insights, tips, and more.