Remix: Something different
Tags: react, webdev, beginners, remix
Published: 2022-02-12 22:50:17

Coming up to three years ago I made the shift away from web development as a hobby to web development as a job. Part of finding the confidence to do that was the learning in public I did here, on dev, so in that same vein I'm going to try my hand at learning [remix](https://remix.run).

Before I get started I should say I'm a front end developer with very minor back end experience. I've used NodeJS before and I've dabbled with PHP and Perl. Also I know NextJS is quite popular and may have even been a better choice to start with but I decided to see what Remix had to offer. I may look at NextJS in the future we'll see how this goes.

I'm going to be following the [Blog tutorial](https://remix.run/docs/en/v1/tutorials/blog) on the Remix website, at least to start with. If I get to a place where I feel things are making sense I may stop following it and see where I end up. Now, without further ado, here we go.

## The setup

Well first things first let’s make a place for us to do the work. I made a new folder called `remix-server`, though the name isn't important, and opened VSCode. In the terminal I entered `npx create-remix@latest` and followed the instructions.

```
Need to install the following packages:
  create-remix@latest
Ok to proceed? (y)

R E M I X

💿 Welcome to Remix! Let’s get you set up with a new project.

? Where would you like to create your app? .
? Where do you want to deploy? Choose Remix if you’re unsure, it’s easy to change deployment targets. Remix App Server
? TypeScript or JavaScript? TypeScript       
? Do you want me to run `npm install`? Yes

> postinstall
> remix setup node

Successfully setup Remix for node.
```

When it asked where I wanted to create the app I just used `.` as that means here, had I wanted to make a new directory I could have written the directory name there like `.\my-dir`.

You may also have noticed I'm using Typescript rather than JavaScript, this is because I'm learning Typescript anyway but if you want to use JS that's fine most of what we write will be transferable, I'm sure.

Once NPM had done its thing I was able to run `npm run dev` and look at the server.

![Remix default screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v5qe75eg0dvy1udrrovq.png)

## Making routes

If we look a the files that have been created you'll noticed we have a folder called `app` and inside it another folder called `routes` in which there is a single file called `index.tsx`, a `tsx` file is a typescript react file you might see `jsx` which is the js equivalent. I had a look inside the index file and saw it was a normal looking react file that contained the contents of the demo page we'd just made.

Reading ahead in the tutorial we see it wants us to modify the index file and make a new route so let's do that but also let's deviate from the script just enough to make sure we know what's going on.

I plan to amend the index file to contain a `Link` as it says to do in the tutorial but then I will make a new directory called test and inside it I will put a file called index and another called inner. I posit I will then be able to got to `localhost:3000`, `localhost:3000/test` and `localhost:3000/test/inner` to see my 3 files.

```tsx
/* base level index */
import { Link } from "remix";

export default function Index() {
  return (
    <>
      <h1>This is a test</h1>
      <Link to="/test">Test page</Link>
    </>
  );
}

/* Index file inside '/test' */
import { Link } from "remix";

export default function TestIndex() {
  return (
    <>
      <h1>This is a test</h1>
      <Link to="/test/inner">Test inner</Link>
    </>
  );
}

/* File called inner inside '/test' */
export default function Inner() {
  return (
    <>
      <h1>You found me!!</h1>
    </>
  );
}
```

And what do you know it works. It seems any directory inside the routes folder becomes a route, if an index file is inside the route it is served when you go to the route directly and any other files can be reached by typing their name after the route in the URL. I'm sure there will be more complexity than this further down the road but that seems to be a good enough understanding for now.

Let's get on with the tutorial.

## Getting data

This section feels a little messy to me, it starts by having you put all your code in a single file then tells you this isn't best practice and has you refactor it. Also, in the typescript version, it has you use type when a interface works perfectly well. I'm going to tell you what I did differently I don't think it will make a massive difference in the end but I feel it's less confusing this way.

### useLoaderData hook

Firstly we need to use a hook called `useLoaderData` we import this from `remix` just like we did for link. This also requires us to have a function exported from the file we're using `useLoaderData` in called loader. It's best practice to make this function `async` as that allows us to wait for data to load. The loader function should return our data in the format we want to ue it in our react file.

```tsx
import { useLoaderData } from "remix";

export const loader = async () => {
  return 'hello world';
};

export default function Posts() {
  const loadedData = useLoaderData();

  return (
    <>
      <h1>Posts!</h1>
      {loadedData}
    </>
  );
}
```

This above snippet would print 'hello world' as `loadedData` would become what the `loader` function returns.

Now if we want to get more complex data from our `loader` it's a good idea to make a new file that contains the function, then import that function into our react file and use it inside the `loader` function. As we don't want this new file to have a route let's go back up to the `app` level and make a new folder called 'loaders' in here we'll make a file called `posts.ts`.

```ts
export interface Post {
  slug: string;
  title: string;
}

export const getPosts = (): Post[] => {
  return [
    {
      slug: "my-first-post",
      title: "My First Post",
    },
    {
      slug: "90s-mixtape",
      title: "A Mixtape I Made Just For You",
    },
  ];
};
```

This file contains an [interface](https://www.typescriptlang.org/docs/handbook/interfaces.html) that describes the data that `getPosts` returns. We also have a function called `getPosts` that simply returns the 'data' we want to get. In the future this could contain some database calls or something but let's keep it simple for now. Both the interface and function are exported so we can use that back in our posts index file.

```tsx
import { Link, useLoaderData } from "remix";

import { getPosts, Post } from "~/loaders/post";

export const loader = async () => {
  return getPosts();
};

export default function Posts() {
  const posts = useLoaderData<Post[]>();

  return (
    <>
      <h1>Posts!</h1>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link to={post.slug}>{post.title}</Link>
        </li>
      ))}
    </>
  );
}
```

As you can see we're importing the interface and the function. The interface lets us modify the `useLoaderData` function which allows us to have auto complete in our IDE by saying the `posts` const is and array of `Post`s as described by the interface.

## Dynamic routes

To add a dynamic route you make a new file in routes directory. The files has to start with a `$` but the rest of the name can be anything you like. In the example given by remix they use `slug` so we'll do the same.

Something magical happens when you do this. The loader function from before can see the URL you've entered and do something with it but let's take a step back and understand what is going on here. 

It turns out the loader function is always past an object that we can use. That object contains a `request` object, a `context`, which was undefined for me, and a `params` object. The request is the full request the server is receiving including the full URL, the method, GET in this case, and even a query which might come in handy later. But now we have a simple understanding of what the loader function can do let's carry on.

The part of the URL we care about is stored in the params part of loaders params and is called whatever the file is called minus the `$`, `slug` in our case. 

```tsx
export const loader: LoaderFunction = async ({params}) => {
  return params.slug;
};
```

`LoaderFunction` is an [type](https://www.typescriptlang.org/docs/handbook/basic-types.html) we imported from remix to keep typescript happy.

## Loading data

We can use normal NodeJS things like fs to load in files from the file system. The tutorial has us create some markdown files out site of the app directory that we can load in.

Using `fs` we can get a list of all the filenames also we can load the post titles, which are inside the md, using `parseFrontMatter`. This data can be structured to replace the old static array of posts.

Now we need a new function that can take our slugs, from the dynamic route, and open the file to display the `md` as html. Once again we use `fs` to load the file then we use `marked` to convert the `md` to html. We call this function `getPost` and once we've imported it into our `$slug` file we're there.

## Recapping

To recap we've,
  - started a new project using npm
  - made some custom routes
  - loaded some data to construct a dynamic list of content
  - read an `md` file and converted it to html
  - displayed that html in a dynamic route

That both feels like a lot but also hasn't felt like too much. We're only half way through the tutorial but this post is getting long so it feels like a good place to get off for now.

Thank you for reading it really means a lot. Please feel free to leave a comment even if it's to tell me what I've done wrong or what I can improve.

If you'd like to connect with me outside of Dev here are my [twitter](https://twitter.com/Link2Twenty) and [linkedin](https://www.linkedin.com/in/andrew-bone-ba241b179/) come say hi 😊.