Remix

Essential React

01 Server-Side Rendering
02 Setup
03 Routing
04 Data Fetching
05 Forms & Actions

Server-Side Rendering (SSR)

React Rendering Mechanisms

Overview

Rendering Mechanisms

How does Pre-Rendering work?

How does Pre-Rendering work?

Advantages of Pre-Rendering

  • Search engine optimization (SEO), shareability
  • Performance (especially as perceived)

Remix

Remix

  • Created by Michael Jackson and Ryan Florence (same as React Router)
  • Remix v1 in November 2021
  • Use the Platform philosophy
  • Only Server-Side Rendering (no SSG)
  • Supports Progressive Enhancement
Remix Website Screenshot remix.run

Setup

Create a new Remix app


                $ npx create-remix@latest pokedex-remix
                  ? Initialize a new git repository?
                    > Yes
                  ? Install dependencies with npm?
                    > Yes
 
                $ cd ./pokedex-remix
                $ npm run dev
            

File Structure

Initial files of Remix app folder
  • app/routes/*.tsx
    route files (more details in next chapter)
  • app/entry.*.tsx
    complete control over server and client entry points (optional)
  • app/root.tsx
    describes the app's HTML document / root layout
  • public/*
    public asset files
  • remix.config.js
    dev server / build options
Initial files of Remix app folder

app/root.tsx

NPM Scripts

npm run dev

Starts the app in dev mode with hot reload

npm run build

Creates a production build of your app (output in build and public/build folders)

npm start

Starts Node.js server in build folder

For deployment to common platforms consider using a template (see README.md)

npm run typecheck

Runs TypeScript compiler to ensure type-safety in build pipeline (not done automatically by Remix compiler)

Routing

Intro to Route File Naming

General conventions

  • Remix uses the same concepts and core logic as React Router
  • Use file names to define routes
  • Route files are placed in app/routes
  • Flat file structure (no nested route folders)
  • Co-location of non-route files is possible

_index indicates an index route

→ URLs / and /blog

Static route segments

→ e.g. /about and/blog/archive

Use the dot delimiter for nested routes

→ URLs /blog/…

Dynamic route segments (parameters) start with a dollar symbol

→ e.g. /blog/five-great-tips-for-2024

See Remix docs for more details.

Route Module API

Route Module API

blog.$slug.tsx

How can we redirect to a different route?

E.g. //blog

How can we redirect to a different route?

E.g. //blog

_index.tsx

Must be a named export called loader.

_index.tsx

→ redirects to blog.tsx

Other Useful Route Module Exports

Data Fetching

Loaders

Loaders

  • Single, optional loader per route (export loader)
  • Run on the server (only)
  • Define a HTTP endpoint: request → response
  • useLoaderData to access response data in component

blog.$slug.tsx

Modifying the HTTP response

Modifying the HTTP response

Return a Response object…

Modifying the HTTP response

…or throw it!

Exercise

Setup & Routing

  1. npx create-remix@latest <app-name>
  2. Set up routes for pokemon list, pokemon detail, and profile pages
  3. Display mock data

Data Fetching

  1. Load the data for the list and detail pages from the Poke API
  2. Show the Not Found page if an unknown pokemon name is passed in the URL
  3. Stretch goal: Transform the data from the PokeAPI so that only the needed data is sent to the client

Solution

app/routes/_index.tsx

app/routes/pokemon._index.tsx

app/routes/pokemon.$pokemonName.tsx

app/api/fetcher.ts

app/components/layout/Layout.tsx

app/root.tsx

Complete solution code can be found on GitHub on the branch 02-data-fetching.

Forms & Actions

Creating a form

blog.$slug.tsx

Let's start simple: We can use a native HTML form.

blog.$slug.tsx

On the server the form is processed by an action.

blog.$slug.tsx

Form data is read from the request using the standard Request.formData() method.

blog.$slug.tsx

The data can then be processed as desired (validated, stored, etc.).

blog.$slug.tsx

Like the loader, the action function can return a Response object.
Typically, a redirect is returned to implement the Post/Redirect/Get pattern.

blog.$slug.tsx

What will happen when the user clicks the Submit button?

→ It works! But it does a full document request: POST /blog/…

blog.$slug.tsx

The Remix Form component brings the expected SPA behavior.

It still has the native form behavior as long as JS has not loaded yet.
→ Progressive Enhancement

Sessions and Cookies 🍪

Remix has built-in support for sessions:

  • Cookies
  • In-memory (dev only)
  • Files
  • Cloudflare Workers
  • Amazon DynamoDB

Let's work with the most versatile one:

  • Cookies

app/sessions.ts

We set up our session handling utilities.

app/sessions.ts

We set up our session handling utilities.

And can use them in server-side code (typically loaders and actions):

Validation (server-side)

What do we want to show in case of validation errors?

The form, with:

  • The field values
  • Validation error messages per field

Thus, what do we need to do differently in our action?

Thus, what do we need to do differently in our action?

If request is invalid, return a HTTP 400 response with the field values and errors.

In the component, useActionData to access the data returned by the action:

Exercise

Forms & Actions

  1. Add a form for name and email to the Profile page
  2. When the form is submitted:
    • Submit the data to the server and store name and email in a cookie
    • User stays on the same page
  3. Display the name in the navigation bar

Validation

  1. Validate the profile form, e.g.
    • Name and email are required
    • Name is max. 25 characters
    • Email is a valid email address
  2. Ensure the submitted data is displayed
  3. Show the validation error messages at the form fields

Solution Forms & Actions

app/components/profile/Profile.tsx

app/components/profile/Profile.tsx

app/sessions.ts

app/routes/profile.tsx

app/routes/profile.tsx

app/routes/profile.tsx

app/components/layout/Layout.tsx

app/root.tsx

Complete solution code can be found on GitHub on the branch 03-forms-actions.

Recap

We learned…

  • What server-side rendering (SSR) is
  • How to set up a Remix app
  • How to do routing in Remix
  • How to fetch data in Remix
  • How to create and process forms in Remix

Questions?