Remix Fundamentals

Data Loading Solution

Kent C. Dodds

Kent C. Dodds

Professional Trainer
Remix Fundamentals

Check out a free preview of the full Remix Fundamentals course

The "Data Loading Solution" Lesson is part of the full, Remix Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Kent walks through the solution to the data loading exercise. The answer to the exercise's help TypeScript extra credit is also provided in this segment.


Transcript from the "Data Loading Solution" Lesson

>> Hopefully you had a good time loading data in a Remix app. So our objective here is we just wanna show a list of the posts that we have. And I gave you some posts to use. Just this, this is our data, oops. So we'll go into app > routes > posts > index, and here's my data.

And then we've got our JSX that we can render for this. So we'll just do that here and bring in { Link } from "@remix-run/react". And then I guess we can just say data.posts, right? And we're done, it works. I'm just kidding, that's not how you do it.

Because then you'd have to change your code every time you wanted to write a new blog post, right? That would be silly, I wouldn't do that. So no, we're gonna use an actual API from Remix, and it's a convention, and that is to export a function called loader.

And it's actually typically an async function. Very rarely will this not be an async function, so we'll just stick an async on there. And then actually, you know what I wanna do? I'm gonna make an async function called getPosts, and that is gonna get me all of this.

There we go, so now I have my posts, getPosts, and I'm going to return a response. So the loader accepts a couple of things we'll talk about later, and returns a response. So we return a new Response. And we're gonna return a JSON response so that our client can get that JSON response.

So I'm gonna say JSON.stringify posts. And then I'll add a header with "Content-Type": "application/json". Cool, so I'm sending that response back. And then in my posts, I'm going to get. Or in my post component, I'm gonna get my posts from useLoader, come on, useLoaderData. And now I've got my post there, cool.

Refresh, boom, there it is. Okay, so let's look at the code really quick, cuz I went through that pretty quick. We're gonna make some modifications to this as well. So the loader is responsible for loading data. And it runs on the server, and only the server, okay? And so you have access to database, you have access to private keys that you don't want shared in the wide, wide world.

You can read the file system if you're not running in a serverless environment or whatever, where that would make sense. Whatever you want to, your only responsibility is to return a response. And the vast majority of the time, that response should be a application/json response. So this looks like a fair bit of boilerplate.

If that's what I do in almost every one of my loaders, it would be really nice if we had a little helper function to help us with that, and so we do. json, and yeah, none of these is correct. It should come from @remix-run/node, so we'll import { json } from '@remix-run/node'.

There we go, cool, and then we say json(posts), and that effectively does the same thing. But I want to call out something special here, something special about Remix. Remix is not just another framework, okay? It is a framework that exposes the web platform to you. So where a lot of libraries that I've written and frameworks that have been written take the web platform APIs and wrap them in what they think is a nicer, cleaner API.

Remix instead exposes the web platform API. And in fact, we're running an Express server under the hood right here. But you can also, again, run on Dino, or you can run on Cloudfare Workers or wherever. I always mix up Fastify and Fastly. One of them's a CDN, the other's a web framework or a node framework.

But wherever you're running, and they all have their different API, like Netlify functions or cell functions, they all have different APIs for request response. What Remix does is it actually acts like a jQuery for the platform, and it turns all of those request responses into a web fetch request response.

And so if you dive into this response, then you see this is the Fetch API. We make the Fetch API global and actually Node 18, I think I believe it has Fetch built in, but I believe it also makes these global. And so wherever you are, we make the response global so that you can work directly with request response, regardless of where you're deploying to.

I think this is a really powerful piece of what makes Remix special. So because we do this a lot, we have a little utility for that because that would just be super annoying to have to do this over and over again, okay? So that was the first part of the exercise.

And what I typically do actually, I typically like to send back an object rather than just the array. So I'm gonna send back an object with a property of posts is one change I wanna make. Now we wanna, I think the next one was to improve the TypeScript piece.

So we wanna make it so that TypeScript isn't yelling at us about this. And of course, we could say any, and now TypeScript's not yelling. But we wanna actually make TypeScript be helpful. We're not just saying hey, TypeScript, hush. We want to have TypeScript to help us because I could very easily make a mistake like that, right?

And now my link is pointing to the wrong place, it's pointing to undefined. I have no way of knowing that that's happening. So here's how you do this with Remix. It just recently got this good, and so I'm really excited to show you. typeof loader, boom, and now you have type safety across the network chasm.

That's pretty rad, I think that's kinda nice, I like that a lot. And what's interesting here is that Remix will ensure that because Remix is managing the network chasm, we can rely on this. The only situation where you could end up with a type error that goes from the loader to the client when you're using this is if some EMP hit and it flipped a bit or something.

So sorry, we can't protect you from natural disasters or anything. But other than that, you're pretty dang type safe just by adding typeof loader to your useLoaderData call. So I think that's pretty neat. And if I decided, hey, you know what? Instead of slug, I wanna have this be the Id.

Well, now I'm getting type errors for that. Id, hurray. It's amazing, it really is cool.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now