Published

frrrip throwing remix.run into the mix my first impressions

Remix.run is the (or not, to be confirmed) hot new Full Stack React framework around the block. A few knowledgeable engineers hype it at the moment. It should be noted that the founders Michael Jackson and Ryan Florence are mostly known for React Router, UNPKG, and Reach UI. Moreover, Kent C. Doddshas recently joined the team as director of developer experience to throw some more wood on the fire. Many developers have used at least one or more things that they made.

In this post, I will be talking about the following:

  • Remix
  • Routes
  • Loaders
  • Client UI
  • Actions → I like this part
  • My opinion

About Remix

The entire idea behind Remix is that everything is server-rendered. As someone who has spent much time using things like Next.js and Gatsby, going mainly SSR is somewhat different.

To begin, their website says: Remix – Build better websites. Saying something like that lifts the expectations and raises the bar to a high level, especially when the competition for creating websites is enormous. Next.js, in particular, is probably the closest competitor for what Remix is trying to do. Moreover, I will not be comparing Remix with something like Gatsby, as Remix isn't a Static Site generator. Instead, the focus of Remix is server-side rendering, and even though you can use Next.js as an SSG, it has server rendering and does a lot of the same stuff Remix does, but differently.

Initial project setup

I have mixed feelings about the initial setup. So let me carry you through this. Firstly, you do this in your terminal:

create-remix command

Following this, you see a fancy Remix animation in the console and a menu where you need to choose where to deploy your application. Depending on your pick, you get a project with different configuration files pre-made for the platform you will deploy. On the one hand, if you want to change hosting, you need to think about what needs to change to run it on the other platform. On the other hand, it doesn't feel great.

On the other hand, it does save you configuration time, it's easy, and the animated logo in the terminal looks pretty. Let's talk about the essential thing about Remix.

Routes

Firstly, routes are the most significant thing about Remix. To me, it feels like every route is a server route and conveniently has the option to render a client-side UI if you want. In essence, everything in Remix is about routes, and that's not a surprise if you look at the people that founded Remix.

Every route is a server route and conveniently has the option to render a client-side UI if you want.

Basically, on every route, you have the option to export things. So, for example, you can render a front-end, get data from somewhere, generate an RSS feed, or submit a form based on those things.

Just going over the basics, these are things you can expect from a route:

export {loader, meta, handle, action, CatchBoundary, ErrorBoundary}
export default <div />

I'm not going to elaborate on the functionalities of Routes (nested routes, parameters, …), but those are things you want to take a look at once you know the basics.

Loader

Loaders are the backbone of the route, as they do all the heavy lifting. Therefore, you want to return to everything related to the data you need in this function's front end.

The idea behind a loader is that you can do more than return data for a route. You can send complete responses, including cache control headers. When you set cache headers on your response, the same route will get the cache if the route has already been fetched.

An example of a loader:

import { json, type LoaderFunction } from 'remix'
export const loader: LoaderFunction = async ({ request, params }) => {
const example = await getExampleData()
return json<LoaderData>(
{ example },
{ status: 200, headers: { 'Cache-Control': 'private, max-age=3600' } },
)
}

Client UI

If loaders are the backbone, the client-UI is the frontal bone. In particular, the part you export as default is where you render your front end. So if you have fetched some data inside your Loader, you can get it here and render it for your visitors.

Getting the data from the Loader is pretty straightforward:

export default function ExamplePage() {
const { example } = useLoaderData<LoaderData>();
return <div>{ example } < /div>
}

Everything else in the default export is basic JSX, putting components where you want them, and so on.

At this point, you could make your entire full-stack application with just these two things. In addition, RRemix makes the communication between the front- and back end pretty darn easy. You can fetch data from any API, and since it is server-side-rendered, you can fetch data with secret keys without worrying about exposing your secrets.

Remix makes the communication between the front- and back-end pretty darn easy.

Action

Last but not least, actions. Actions are where things get interesting. Action is a server-only function where you can handle actions. It is the same as Loader; the only difference is when it's called. The action is called before the loaders if a non-GET request is made to your route (POST, PUT, PATCH, DELETE).

For example, an action could be submitting a form to subscribe to a newsletter.

First, we create a simple form like this:

import { Form } from { remix }
export default function ContactFormRoute() {
<Form noValidate method="post" >
<h2>Sign up for our newsletter </h2>
<input name="email" type="email" />
<button>Subscribe</button>
</Form>
}

Remix <Form> works identically to HTML <form>, with a few goodies. If JavaScript is turned off, the form will still work. Remember, the default form only supports GET en POST, so you should probably stick to those if you’re using a form.

And then, we create a server-side Action to handle the form submission. When no action is provided to a form, it will submit to the page itself.

export const action: ActionFunction = async ({ request }) => {
if (request.method === 'POST') {
const formData = await request.formData()
const email = formData.get('email')
// handle server side validation
if (!email) {
return json({ errors: 'no email provided' }, 500)
}
// subscribe login return 500 when things go wrong
return json({ ok: true }, 200)
}
}

To get back to the front end, you can receive the responses from the action in a few ways, one of them being useActionData.

const actionsData = useActionData()
if (actionsData?.ok) return <div>success! </div>
if (actionsData?.errors) return <div>{actionsData?.errors} </div>

When a POST is made to a URL, multiple routes in your route hierarchy will match the URL. Unlike GET to loaders, where all of them are called to build the UI, only one action is called.

Forms without an action prop (<Form method="post">) will automatically post to the same route within which they are rendered.

My first thought was: Oh, you can build an entire API like that. Nice. It’s the /api folder in Next.js (if you are familiar) but throughout the entire routing folder. Moreover, every route has the option to render a front end. That’s amazing.

With loaders and front-end rendering, you have all the basics to make an application. Everything else is improving the UX of the application.

Other stuff

Remix doesn’t stop at Loaders and Actions. My first impressions do, however. If you want to know more about Remix (like nested routes, Error handling, and so much more), I would strongly suggest looking at their website: https://www.remix.run.

My opinion about remix.run

Honestly, I can say that I’m hyped. I am a fan of serverless and JAMStack, so I started sceptically. Remix.run, to me, feels like you are working inside a web framework, not a React framework. You so happen to be, are working with React on top of it. Moreover, I have learned about Javascript in my adventure learning Remix, and I’m not done using it. It is promising without a doubt.

In conclusion, a lot of things make sense. Thinking about what happens on the server and what doesn’t is something extra to think about, but that might be a good thing.

If you are a fan of magic, I recommend you to stick to Next.js (or Gatsby for even more magic) or whatever framework you are using now. But if you like bare-boned where you have control over everything, Remix might be your tool.

Done reading?

Read more related articles