You are NOT signed in as a student! Your progress will not be saved and you won't see milestones on your ZTM Passport.
Make sure you are logged into
Academy
Autoplay
Autocomplete
Previous Lesson
Complete and Continue
Remix (React Router) Bootcamp: Zero to Mastery
Introduction
Course Outline (5:40)
What is Remix? (2:20)
Why Remix? (6:36)
Remix vs React Router (2:12)
Intro to the Master Project (3:51)
The Recipe Page & Optimistic UI (7:23)
Finishing the Tour of the Master Project (5:38)
Exercise: Meet Your Classmates and Instructor
ZTM Plugin + Understanding Your Video Player
Course Resources
Set Your Learning Streak Goal
Remix Overview
Installing NodeJS (2:02)
Creating a React Router Project (1:29)
The Vite Config File (1:09)
Upgrading Remix and Future Flags (3:32)
Owning Your Entry Points (2:12)
What are Routes? (2:48)
Exercise: Identifying Server and Client Components in Remix Routes
Solution
Let's Have Some Fun (+ More Resources)
Basic Routes and Styling
An Explanation of New Imports
Nested Routing (6:31)
Exercise: Nested Routing in Remix
Solution
The Root Route (3:15)
Exercise: Understanding Matched Routes with useMatches
Solution
Remix's Special Components (3:41)
The Link API (3:05)
Adding Style with Links (7:13)
Exercise: Utilizing the links Route Export in Remix
Solution
Techniques for Component-Level CSS (7:44)
Setting Up Tailwind (3:38)
Using Tailwind - Part 1 (4:26)
Using Tailwind - Part 2 (5:45)
Using Tailwind - Part 3 (5:09)
Unlimited Updates
Introduction to Data Loading in Remix
What are Loaders? (9:34)
Exercise: Remix Loaders
Solution
Pending UI (9:06)
Exercise: Implementing Pending UI on Links in Remix
Solution
Why Load Before Route Transitions (9:43)
Sharing Data Between Routes (3:53)
Exercise: Revert the changes from the last lesson
Errors and Error Boundaries (5:52)
Exercise: Handling Errors with Error Boundaries in Remix
Solution
Installing Postgres with Docker (15:09)
Setting Up Prisma with Postgres (7:15)
Implement a New Life System
Master Project: Remix Recipes App (The Pantry Page)
Overview (2:25)
Setting Up the Pantry Route (11:03)
Redirects in Remix (7:04)
Exercise: Experimenting with HTTP Status Codes
Solution
Setting Up the Pantry Database Tables (13:12)
Seeding the Database (9:13)
Database UI Tools (9:36)
Loading Data into the Pantry UI (5:12)
Creating a Model Abstraction (10:37)
Building a Basic Shelf UI (10:53)
Intro to HTML Forms (21:34)
Exercise: Exploring Similarities Between HTML Forms and Anchor Tags in Remix
Solution
Enhancing the Search Bar with JavaScript (8:16)
Exercise: The FormData Object
Solution
Creating Shelves (14:11)
Enhancing the Create Shelf Button (8:09)
Deleting Shelves (18:45)
Handling Multiple Deletes (6:57)
Introducing useFetcher (7:30)
More Cases for useFetcher (2:05)
Server State in Remix (4:27)
Exercise: Understanding Concurrency in Remix
Solution
Editing Shelf Names (12:27)
Validating Forms with Zod (18:44)
Intro to Optimistic UI (9:19)
Optimistically Deleting Shelves (12:56)
Creating Shelf Items (7:21)
Deleting Shelf Items (11:56)
Optimistically Creating Shelf Items (21:45)
Suppressing the Layout Effect Warning (4:23)
Optimistically Deleting Shelf Items (8:17)
Additional Enhancements (14:16)
Course Check-In
Authentication Prerequisites
Overview (1:32)
The User Model (7:40)
The Login Route (10:10)
Intro to Cookies (2:24)
Setting Our First Cookie (3:41)
Cookie Attributes (7:27)
A Simple Auth Flow (6:20)
Remix's Cookie Helper (5:04)
Exercise: Cookies
Solution
Cryptographic Signatures (4:09)
Signing Cookies (1:45)
Signing Cookies in Remix (4:27)
Sessions (3:42)
Session Storage (4:02)
Session Storage in Remix (7:10)
Magic Link Authentication
Overview (2:45)
What is Authentication (2:02)
Overview of Magic Link Authentication (2:51)
Magic Link Structure (1:51)
Generating Magic Links (7:46)
Updating the Login Route (3:57)
Validation Route Overview (1:49)
Parsing the Magic Link Payload (8:36)
Validating the Expiration Time (3:09)
Validating the Nonce (6:04)
Finishing the Login (2:42)
The Sign Up Form (8:12)
The Sign Up Form Action (9:37)
Signing Up for Mailgun (3:48)
Setting Up the Mailgun Client (6:16)
Sending the Magic Link Email (6:08)
Showing the Check Email Message (2:19)
Authorization
Overview (2:52)
Authorization Rules for the Login Page (2:26)
Login Authorization Rule #1 (6:19)
Login Authorization Rule #2 (1:06)
Authorization Rules for the Pantry Page (5:54)
Pantry Authorization Rule #1 (2:42)
Pantry Authorization Rule #2 (1:40)
Pantry Authorization Rules #3-4 (2:15)
Pantry Authorization Rules #5-6 (3:43)
Pantry Authorization Rule #7 (2:22)
UI Updates Roadmap (2:15)
Adding an Error Boundary (7:30)
Hiding the App Nav Button (3:03)
Creating a Logout Route (5:28)
User Interface (The Recipe Page)
Overview (4:05)
Revisiting the Remix Philosophy (3:28)
Setting Up the Recipes Route (4:34)
Setting Up the Recipe Database Tables (3:55)
Updating the Seed Script (4:23)
Recipe Page Components (1:44)
The Recipes Loader (5:59)
Rendering the Recipe List (4:19)
Creating a Search Bar Component (7:46)
Supporting Search in the Loader (2:09)
The Create Recipe Form (4:51)
Setting Up the Recipe Detail Route (4:44)
Exercise: Exploring Dynamic Route Segments in Remix
Solution
Sorting the Recipes List (1:35)
Preserving the Search Parameters (6:17)
Recipe Link Pending UI (5:41)
Exercise: Writing your own Hook to Delay the Pending UI
Using Link Prefetch (8:19)
Recipe Detail Route Overview (1:39)
Overview of Step 1 - Creating an Input Component (6:40)
Displaying the Name and Total Time (10:13)
Rendering the Ingredients (7:24)
Rendering the Instructions (6:30)
Overview of Step 2 - Updating Recipes (1:03)
Saving the Recipe Name, Total Time, and Instructions (8:32)
FormData's getAll Function (4:01)
Updating the validateForm Function (8:28)
Updating the Ingredients (8:05)
Creating New Ingredients (7:28)
Addressing and Issue (4:08)
Adding Error Messages to the UI (7:39)
Exercise: Imposter Syndrome (2:55)
Overview of Step 3 - Deleting Recipes and Ingredients (0:32)
Deleting a Recipe (2:27)
Deleting Ingredients (3:38)
Authorization Rules for the Recipe Detail Route (1:50)
Recipe Detail Authorization Rule #1 (2:55)
Recipe Detail Authorization Rules #2-5 (2:07)
Enhancement Overview (2:34)
Overview of Step 1 - Saving Inputs on Change (1:19)
Saving Recipe Inputs on Change (8:22)
Creating an Ingredient Row Component (5:52)
Saving Ingredient Inputs on Change (4:03)
Persisting the Recipe Fetcher Data (6:50)
Persisting the Ingredient Fetcher Data (5:06)
Debouncing Form Inputs (2:06)
Creating a Hook for Debouncing (7:03)
Debouncing the Form Inputs (3:31)
Overview of Step 2 - The Case for Optimistic UI in the Side Bar (2:01)
Updating the Side Bar with useFetchers (5:46)
Overview of Step 3 (3:39)
Wiring up a Fetcher to Create New Ingredients (9:27)
Creating a Hook for Optimistically Rendering Ingredients (5:17)
Optimistically Rendering New Ingredients (4:58)
Updating the Default Enter Key Behavior (4:14)
Creating Mew Ingredients with the Enter Key (1:54)
Focusing the Amount Input on Create (4:47)
Optimistically Deleting Ingredients (3:43)
File Uploads
Overview (1:22)
Creating a File Input (3:26)
The Urlencoded Content Type (5:35)
The Multipart Content Type (5:29)
Parsing Multipart Forms (1:26)
Overview of Parsing Multipart Forms in Remix (5:16)
Remix's Built-In Upload Handlers (3:47)
Storing Images in the Public Directory (3:15)
Writing the Image URL to the Database (3:09)
Exercise: Implementing Custom File Upload Handler in Remix with Cloudinary Simulation
Solution
Remix Modals (The Grocery List)
Overview (3:29)
Updating the DB to Track Meal Plans (2:18)
Modals in Remix (4:29)
Setting up the Modal Route (4:59)
Creating some Components for the Modal (5:25)
Meal Plan Modal UI (5:43)
Passing Context to the Outlet (4:46)
Creating the Modal Action (5:22)
The Update Meal Plan Action Case (6:18)
Indicating which Recipes are in the Meal Plan (3:31)
The Meal Plan Filter Button (7:00)
The Meal Plan Filter Backend (2:26)
Preserving the Search State when Filtering (5:17)
Preserving the Filter State when Searching (3:48)
Overview of Next Steps and Setting up the Grocery List Route (2:21)
Defining the Grocery List Item Type (4:16)
Building the Grocery List Item Component (6:16)
Getting Started on the Grocery List Loader (6:16)
Formatting the Missing Ingredients (3:35)
Grouping Grocery List Items by the Ingredient Name (6:05)
Rendering the Grocery List (2:35)
Creating the Grocery List Route Action (4:28)
Adding Grocery Items to the Pantry (6:20)
The Grocery List Empty State (3:17)
Clearing the Meal Plan (6:13)
Resource Routes in Remix (The Settings Page)
Overview (1:28)
The PageLayout Component (4:05)
Setting up the Settings Route (2:30)
Intro to Resource Routes (2:38)
MIME Types (5:45)
Exercise: MIME Types
Solution
Overview of Customizing the Theme (2:33)
Renaming the Resource Route (1:45)
Controlling the Tailwind Theme with the Theme Resource Route (5:01)
Building the Form to Change the Site Theme (3:49)
Creating the Theme Cookie (2:08)
The App Settings Route Action (4:04)
The App Settings Route Loader (2:50)
Fixing the Off-By-One Issue (5:19)
Returning Dynamic CSS Based on the Theme Cookie (3:31)
Caching (The Discover Page)
Overview (0:52)
Redirecting the Home Page (1:17)
The Discover Page UI (4:37)
Discover Detail Page Setup (2:44)
Discover Detail Page UI (3:06)
Intro to Caching (1:47)
Private vs Server Caches (3:09)
Preview of Using the Browser Cache (3:41)
Caching Vocabulary (2:35)
The Default Browser Strategy (3:31)
The No-Store Strategy (1:23)
The Fixed-Time Strategy (1:21)
The Cache-Busting Strategy (4:09)
The Revalidate-Once-Stale Strategy (1:44)
Etags (4:03)
Responding to the If-None-Match Header (3:12)
The Stale-While-Revalidate Strategy (4:21)
Caching Full HTML Pages (2:28)
Responding to If-None-Match on HTML Requests (5:39)
Testing
Introduction to Testing (1:00)
Setting Up Playwright (1:59)
Writing our First Test (6:51)
Creating Dynamic Routes (7:00)
Implementing the Test Login Route (4:53)
Testing a Typical Pantry Page Flow (7:17)
Finishing up the Pantry Test (4:04)
The Playwright UI (2:22)
Creating a Delete User Test Endpoint (4:23)
Deleting Test Users (1:41)
Exercise: End-to-End Testing with Playwright
Solution
Deployment
Deployment Overview (0:44)
The Fly CLI (2:47)
Prisma MIgrations (3:27)
Creating the Database Server (3:14)
Creating the App Server (1:38)
Setting Environment Variables (3:26)
Deploying the App (1:09)
Appendix: Upgrading Remix
An Example of Upgrading Remix (13:51)
Where To Go From Here?
Thank You! (1:17)
Review This Course!
Become An Alumni
Learning Guideline
ZTM Events Every Month
LinkedIn Endorsements
Overview
This lecture is available exclusively for ZTM Academy members.
If you're already a member,
you'll need to login
.
Join ZTM To Unlock All Lectures