Remix: Finishing the tutorial
Tags: react, javascript, webdev, beginners
Published: 2022-02-13 19:22:54

Yesterday I started a new series to follow my journey into learning [Remix](https://remix.run/), we got about halfway through the [blog tutorial](https://remix.run/docs/en/v1/tutorials/blog#creating-blog-posts) which meant we had routes and could load posts dynamically from the file system. Today we're going to work through the rest of the tutorial.

## Making an admin section

The tutorial barrels on having us use many things we've already learnt to create a new route and populate it with data.

### CSS and styles

I was quite surprised that this section very quickly moved on to how to link CSS files to your front end, not that isn't something we need but rather I'd have thought it would be something introduced much earlier.

The process is similar to how you would create a CSS file for a single page app. You create a `styles` directory, though the name isn't important, inside the `app` directory. Within the newly created `styles` directory you make a CSS file, we'll call ours `admin.css`.

To import our CSS file we use another magic function, just like the loader function from last time.

```tsx
import adminStyles from "~/styles/admin.css";

export const links = () => {
  return [{ rel: "stylesheet", href: adminStyles }];
};
```

As you can see we import our CSS and then return it inside an array from our links function. Because I knew the loader function took props I decided to console log out any props that the link function may have been getting. Sadly, all I got was `undefined` but no harm in looking.

As an aside, whilst I love CSS I know CSS-in-JS solutions and SASS/LESS are widely used and I prefer them myself. The tutorial doesn't go into how to use these things but a quick google showed me it was indeed possible.

### Nesting routes with an outlet

The tutorial advices us to "Hang with [them]" at the start of this section as we have to unlearn a pattern that was asserted earlier on.

We have been lead to believe that, in the routes folder, we can make a file like `url.tsx` and if you go to `/url` our react code will load. We have also learnt that we can make a directory called `url` with a file inside it called `index.tsx` to achieve the same end. Both of these statements are true however we were also taught that `url.tsx` would supersede `url/index.tsx` but this is not entirely true.

Whilst it is true that, out of the box, `url.tsx` would be displayed we can use `Outlet`, imported from remix to display `url/index.tsx` or, in fact, anything inside the `url` directory as a nested component. This can be a little confusing at first but is helpful for navs, let's make a silly example.

```tsx
/* our nav file called sites.tsx */
import { Outlet, Link } from "remix";

export default function Site() {
  return (
    <>
      <nav style={{ display: "flex", gap: "1rem", justifyContent: "center" }}>
        <Link to="/sites/dev">Dev.to</Link>
        <Link to="/sites/twitter">Twitter</Link>
        <Link to="/sites/facebook">Facebook</Link>
      </nav >
      <Outlet />
    </>
  );
}

/** 
 * our individual files called /sites/dev.tsx, 
 * /sites/twitter.tsx and /sites/facebook.tsx
 */
export default function Dev() {
  return <h1 style={{ textAlign: "center" }}>I love Dev.to</h1>;
}
export default function Twitter() {
  return <h1 style={{ textAlign: "center" }}>I like twitter</h1>;
}
export default function Facebook() {
  return <h1 style={{ textAlign: "center" }}>I tolerate facebook</h1>;
}
```

![gif. clicking between nested components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6r539lde3c0l4gjrnjlf.gif)

As you can see the content of the page changes to match the sub page, as does the URL, but the nav from `site.tsx` is shown first allowing us to have multiple pages with differing content surrounded by a single wrapper.

## Actions

Actions, it seems, are a way to send data back to the server akin to a post request. In fact, as we'll soon learn, it is just that. A post request.

### Form Element

To start with we need a form element, not too dissimilar to PHP development, rather than a standard form element though this is one imported from remix, we wrap our inputs and submit button with the imported `<Form>` which we can give a method. The example method we're given with this tutorial is POST so that's what we'll use.

When we fill out the form we get an error, this is because we haven't got our magic function set up yet. Surprisingly, at least to me, our site doesn't try and post anything when we press submit we just get an error in the console.

```
Error: Route "routes/admin/new" does not have an action, but you are trying to submit to it.
```

### Another magic function

This is our third and final magic function for this tutorial, we've had `loader`, `links` and now `action`. Just like the `loader` function from last time `action` receives a request object, a context something and a params object.

We can get our form data from the `request` and then get each string based on the name of the input. We can do our error handling inside the `action` function and, if there is an error, return an object of errors.

If the `action` functions returns successfully you can redirect the user back to the admin section or even to the post they've just created.

### Error and Loading hooks

The two hooks we're going to use are; **useActionData** for the errors and **useTransition** for the loading state. 

#### useActionData 

As you may have guess, though there's nothing harm if this is news to you, `useActionData` is not a hook solely for error handling. It is, however, a hook for looking at what is returned from our `action` function.

If you recall earlier I said we can return an object of errors. In the tutorial the way that works is if any of the form data is blank it will return an object, halting the request, the object will contain a key for any field that is blank with the value true. For instance,

```js
{
  title: true,
  markdown: true
}
```

The above object is what `useActionData` will return. Meaning we can conditionally render warnings based on what the object contains.

### useTransition

The `useTransition` function returns an object with 4 keys; `state`, `submission`, `location`, `type`.

 - **state** - is a string
 - **submission** - is undefined or is an object
 - **location** - is undefined or is an object
 - **type** - is a string

In the tutorial we use `submission`, which is undefined when nothing is happening, to conditionally change the text inside our button to give some feedback to the user.

## The end

Well that's the end of the tutorial, we've made a system that can dynamically read markdown in order to populate its navigation and also a way to send data from a form back to the server in order to write new markdown files.

What would you like to see next? I have a couple of options that I think are possible from here. I can either take what we have so far and make it look nicer, maybe with styled-components, and maybe even hook it up to a database rather than using the file system. Or I can make something completely different but trying to use the patterns we've learnt so far.

Either way the next project won't be a tutorial follow along it will be me coding and sharing what I've learnt along the way. I think I'll keep all the code on github too, unlike this project that I kept local.

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 😊.