In recent years the development of web applications based on React has seen the rise of new frameworks, each with its own unique approach to simplifying the process of creating modern and high-performance applications.
One such framework that has caught the attention of the developer community is Remix, conceived by the well-known creators of React Router, Ryan Florence and Michael Jackson. But what makes Remix a worthy alternative to Next.js, one of the most established React frameworks?
Remix Features
Remix is a React-based web development framework. It is designed to simplify the development process of modern web applications and provides a wide range of advanced features.
Here are some of the key features that make Remix interesting for developers:
Server-Side Rendering
The main feature of Remix is Server-Side Rendering (SSR) which generates the markup and content of our pages from the web server before sending it to the client. Actually, the benefits of this technology are many:
- Faster Initial Page Load: Since the server sends the fully rendered HTML page the time required for the browser to download and process JavaScript files is reduced, thus improving the user experience.
- Improved SEO: Pages are easier to scan and to index because their HTML content is made available in advance. This improves the visibility of web pages in search engine rankings and helps drive traffic to the website.
- Enhanced User Experience: With SSR, users receive a pre-rendered page from the server, allowing them to view content more quickly and navigate the website seamlessly, providing a smoother and more engaging user experience.
- Cross-platform Functionality: SSR ensures consistent rendering across various devices and platforms, including different browsers, operating systems, and screen sizes. By generating HTML on the server, SSR reduces the inconsistencies associated with Client-Side Rendering (CSR) and ensures a consistent experience for all users.
Here are some additional features in Remix that can streamline your development process:
- Nested Routes: Remix allows you to manage multiple paths using JavaScript/TypeScript files that contain management functions. The files you create are managed by React Router 6, which uses them to generate their respective URLs, following the file system hierarchy.
- Simplified Forms Management: One of the key features of Remix is how it automatically keeps your user interface in sync with the server state. This is done in three steps: route loaders provide data to the UI, forms post data to route actions that update persistent state and loader data on the page is automatically revalidated. Form handling is primarily managed by the “action” and “loader” functions: these functions are built-in, so their names can’t be overwritten. When the user submits data via the form, a number of steps are taken: Remix sends data to the action function; when the action is complete, the loader is invoked to get the new state from the server, and uses the useLoaderData hook to retrieve the data sent by the server.
- Centralized State Management: With Remix, it’s possible to manage server and client-side states directly within the application components: a crucial aspect as it eliminates the need for external tools such as Redux. For example, it’s possible to find out when a page is in the “submit” state, indicating that the form data is being submitted.
- Optimized Error Handling: Remix allows the direct handling of errors within the component, ensuring that when problems arise, the error is only displayed in the component where it occurred, preventing it from crashing the entire application and disrupting the user experience. Error handling is managed by the ErrorBoundary function, which is called when an error occurs in the component, as well as during loader and action functions. In particular, it enters the if isRouteErrorResponse block, in the case of the latter and during rendering.
Main differences between Remix and Next.js
While there are several React-based frameworks, Next.js stands out among them. It is, therefore, useful to analyze the differences between these two tools in order to better understand which might be considered better for web application development.
Static Site Generators
One of the main differences between Next.js and Remix is the use of Static Site Generators (SSGs), which Remix does not support. In any application that uses it, you may encounter a scenario that is not supported by SSGs, specifically dynamic pages. If SSGs cannot be used, the application will retrieve search results from the user’s browser, slowing down the information retrieval process.
On the other hand, Remix is faster because, without supporting SSGs, it uses SWR (HTTP stale-while-revalidate) or Redis to manage information caching in browsers. The speed difference becomes evident when Next.js SSGs cannot be used. Next.js has introduced what is known as the “network waterfall request chain”, which results in delayed loading of page elements as data is retrieved only after JavaScript has been loaded, parsed, and evaluated. With Remix, having a single dynamic way to generate pages allows for changes to cache management without changing the code.
Layout
Another difference between the two tools is the folder structure for building pages and layouts. In Remix, pages and their respective layouts are created based on the given filename. For Next.js, the distinction between pages and layouts is based on the given filename. Files in Next.js are organized into folders and subfolders. Within this structure, you can create the file “page.tsx” to establish a route or“layout.tsx” to create a layout specific to the page.
It may be evident that over the course of a Next.js project, too many page and layout files can accumulate, which can lead to confusion when trying to retrieve them. However, the ability to create files such as “loading.tsx” or “error.tsx” in addition to these two pages helps to define and separate the page states in a more understandable way. On the other hand, just by reading the name of the file, you can immediately understand its contents, so the structure of Remix could be considered more intuitive.
Data Fetching
In Remix, the data is retrieved using the loader function and its corresponding hook, the useLoaderData function. Since it is possible to define a loader on any route, including layouts, data can be loaded in parallel rather than sequentially.
Regarding Next.js, with the introduction of Next.js 13, there has been a shift away from defining data retrieval logic solely on the server side using “getServerSideProps” and “getStaticProps” to the adoption of React Server Components (RSCs). RSCs are components that are rendered entirely on the server, and unlike traditional server-side rendering in React, they are never hydrated on the client. This comes with advantages such as data retrieval and security, as data is never exposed to the client, and deterministic bundle sizes, as components on the server are not downloaded to the client but remain on the server. However, there are also drawbacks, as these components cannot contain interactive parts of the user interface, such as useState and useEffect, and event handlers.
In addition, it is not possible to import a Server Component into a Client, as the Server Component runs only on the server. Despite the convenience of loader functions and the ability to load data in parallel offered by Remix, Next.js Server Components are currently considered more useful. This is due to the various advantages described above and the excellent developer experience. They allow you to compose your component tree in a way that fetches data exactly where it belongs, rather than just in route segments.
Data Mutations
Remix encourages the use of any part of the application where the user performs an action, such as an HTML form. This allows developers to manage an application using a “full-stack data flow” with action and loader.
Next.js 13.4 introduces server actions, which replace API endpoints. With server actions, you can easily create asynchronous server functions that can be called directly from your components, providing access to all server-only utilities such as cookies, revalidate, redirect, and more.
The Remix approach is straightforward and comprehensive for creating a full-stack dataflow application, improving both the user experience and developer experience. However, as complexity increases, there may be a need to reuse an action in multiple places, which requires the action URL to be specified in the form’s action attribute. This can lead to confusion when trying to locate the file that executes the action. Next.js server actions address this issue by allowing you to create functions and import them as needed in the application.
The Community
Next.js has been around for a while now and has a large community. If you have a problem or need help with a particular use case, it’s likely that someone else has already faced the same problem and found a solution. There are also various packages available for many use cases. For example, NextAuth is one such package that is often used to add authentication to a web application.
On the other hand, Remix, being relatively new, is still building its ecosystem. This means that you may have to rely on your own efforts for certain issues.
Conclusions
Remix can be considered a powerful framework, emerging as a valid alternative to the most popular Next.js. While Next.js maintains its widespread appeal, Remix’s unique feature set can significantly impact your development decisions.
Choosing between them depends on your project specific priorities, your team’s development preferences, and familiarity with both framework.
Main Author: Marika Fabiani, Junior Front-end Developer @ Bitrock