Logo

How I learnt Remix.run after moving from NextJS

SS
Saad SiddiquiSenior developer
PUBLISHEDDec 2, 2022
TAGS
reactjsnextjsremix
SHARE

I've been using ReactJS since a while now for building websites and web applications. After knowing the difference between SPA, SSG and SSR of the application, developers accross the React ecosystem primarily moved towards NextJS as it enabled React-based web applications with server-side rendering and generating static websites which helps for better SEO of your application with additional features.

Having the access to have multiple routes in our application, NextJS makes it very convenient for us to handle all our pages. If you already have some experience in building an application with NextJS then remix.run would be your cup of tea. Remix.run practically has the same structure as NextJS but the way it is approached is a bit different.

We will discuss the conecpts of remix which is primarily required in every application.

First let us create a new remix application:

npx create-remix@latest blog-app

I have named my app blog-app you can name it according to your requirements for more details about creating a remix app, checkout Create new Remix App.

Pages (Routes)

First what we have is the pages where we define our routes in the application where all the data is displayed. Let us edit the main index.tsx file in the routes directory.

import { Link } from "@remix-run/react";

export default HomePage(){
  return(
    <main>
      <Link to="posts">
        <h1>Read Blog Posts</h1>
      </Link
    </main>
  )
}

The way routes are created in remix is inside the routes directory. Let's create /posts route in our application

cd blog-app
cd app/routes
mkdir posts && cd posts
touch index.tsx

So now our file structure should look like this:

app
├── root.tsx
└── routes
    ├── posts
    │   └── index.tsx
    └── index.tsx

Edit the index.tsx file in posts folder:

export default function PostsPage() {
  return <h1>Posts List page</h1>;
}

You can create your own route in your application, the posts route is for the demonstartion.

Fetching data

As we have created a route in the application, we need to have data to be rendered on the page. The way we fetch data in remix is by writing a loader function in the route. For more details about loaders, checkout remix loader.

Now inside our posts route we want to list all the blogs which are posted. The way we fetch data in remix is:

export const loader = async () => {
  // fetching random blog posts
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  const result = await response.json();
  return result;
};

export default function PostsPage() {
  return <h1>Products page</h1>;
}

Note: The data we fetch in loader is done on the server-side which is similar to NextJS getServerSideProps.

Managing data

After fetching the data, we would want it to display on the frontend. The data which we fetched in the loader can be accessed by useLoaderData hook. To know more about the hook, checkout remix useLoaderData hook.

The useloaderData hook stores the data that is fetched in our loader function and allows us to use it on the frontend. The way we get the fetched data is:

import { useLoaderData } from "@remix-run/react";

export const loader = async () => {
  // fetching random blog posts
  const response = await fetch("https://jsonplaceholder.typicode.com/posts");
  const result = await response.json();
  return result;
};

export default function PostsPage() {
  // access the fetched data from our loader function
  const data = useLoaderData();

  return(
    <div>
      <h1>Posts List.</h1>
      {data.map((post, index) => (
        {/* render the title and content here */}
      )}
    </div>
  )
}

We can access the data only in the specific route. We can write loader functions in each of our route.

Posting data

We have already discussed about how we fetch the data and then display it on our web page. In every dynamic applications users/customers have the access to make POST requests to upload and post data. In remix the way we post data is using action function, checkout more about remix action.

Whenever we upload data we make a request to the server, in remix we use the <Form /> component and specify the type of request we want to make, the way we post data in remix is:

import type { ActionArgs } from "@remix-run/node";
import { redirect } from "@remix-run/node";
import { Form } from "@remix-run/react";

export const action = async ({ request }: ActionArgs) => {
  // get the input values from the form
  let formData = await request.formData();
  let values = Object.fromEntries(formData);
  // make a POST request
  const res = fetch("YOUR_API_URL", {
    // --> YOUR LOGIC HERE
  });
  return json(res);
};

export default function PostsPage() {
  return (
    <div>
      {/* create a form to submit data */}
      <Form method="post">
        <input placeholder="Enter title" name="title" />
        <textrea placeholder="Enter body content" name="body" />
        <button type="submit">Post</button>
      </Form>
    </div>
  );
}

In the above code we made a POST request and added the data. This just does not finishes here, we also need some better user experiences while using our application so we need to manage the loading and input states.

For the loading state we do not need another useState hook, in remix we can simply handle it by using it's useTransition hook. For further understanding checkout remix useTransition. The way we handle it:

// make an import
import { useTransition } from "@remix-run/react";

  // call inside main function
  const transition = useTransition();
  const isPosting = transition.state === "submitting";

  // inside HTML code
  <button type="submit">{isPosting ? "Posting..." : "Post"}</button>
}

Here we handled the loading state of the form, now we also want to clear the inputs after submitting the form. The simplest approach I prefer going with is:

// import statement
import { useRef, useEffect } from "react";

// inside main function
const formRef = useRef<any>();
// reset the form after done submitting
  useEffect(() => {
    if (!isPosting) {
      formRef?.current.reset();
    }
  }, [isPosting]);

  // inside the HTML
  <Form method="post" ref={formRef}>
  {/* inputs here */}
  </Form>

In the above code examples we have discussed how to create a route, fetch data, load data on the frontend, make a POST request and handle input and loading states.

Now we will discuss about few of the features which stands out for remix.

Error Boundaries

We often tend to make errors in our application when we are in development and we see a huge horrible screen as soon as we make an error, because the entire application breaks when an error is occured because there are no boundaries set for the errors.

In remix.run we can simply manage errors of pages and components individually by ErrorBoundary, without breaking the entire application. There are two ways to handle it, Root Error Boundary and Nested Error Boundaries. I prefer to go with Nested Error Boundaries, the way we handle errors is:

export default function PostsPage() {
  // render HTML
}

// write this code below your main function
export function ErrorBoundary({ error }: { error: Error }) {
  return (
    <div className="bg-red-200 text-red-700 border-2 border-red-500 text-center py-10 px-5">
      An error occurred: {error.message}
    </div>
  );
}

What this will do is, it will catch errors and render the ErrorBoundary component, which in result will not break your entire application but will only show error on the desired component.

This will make our development much faster than to spend time on trying to figure out where the error is, it will simply tell us where it is.

Note: You can customize your own ErrorBoundary component, this example is how I prefer to render it.

In the above examples we went through the primary things which is required to build any application. We discussed about routes, fethcing data from loader function, using the fetched data on our UI, posting data and handling errors using ErrorBoundary.

If anyone has a prior experience with using NextJS then learning Remix would not be as difficult as it seems to be. Remix gives a handy mixture of frontend and backend at the same place and also handling errors in a different manner makes it stand out from other frameworks or libraries.

The topics we discussed are almost similar to NextJS if we understand it. Remix.run has vast concepts which we will surely cover in the next series of the remix.run

HeisentechStay up to date with all Heisentech news
Logo

We believe every owner or business leader knows what is needed to better their business. If you are amongst those people, and want digital tools to get you there, we are here to assist you. If you are not aware of which processes in your business can be transformed, worry not, we will assist you. Either way, let's have a consultation call.

Mumbai, India
Shivdarshan CHS, Bhandup(W), Mumbai - 400078.

©2021 All right reserved. heisentech solutions pvt. ltd.