snow-mountain

Building Your First Web App With Remix


Last updated on
ReactRemixWeb Development

Summary (TL;DR): In this article, we discuss how to build web apps using Remix — a React-based framework with server-side rendering. We’ll cover the benefits (such as faster data rendering, routing, nested pages, and error handling), the disadvantages (such as styling approach, community and the fact that it only does server-side rendering), compare it to Next.js and Gatsby, and finally, show how to build a Todo app using Remix.

Technology is rapidly advancing with a massive inflow of frameworks and libraries, especially in the React and JavaScript ecosystem, all aimed at improving developers’ workflow.

In this article, we will dive into building web applications with Remix. Remix is a React-based framework with server-side rendering functionalities that focuses on user Interface while keeping to web standards. Using Remix means that you can create the frontend and the backend of any web app.

While You Are at It, Why Not Learn More About The Newest Version of React – React 18

Table of Contents

The Benefits of Using Remix
>> Faster Data Fetching
>> Routing
>> Nested Pages
>> Error Handling
The Drawbacks of Choosing Remix for Web Apps
>> Only Does Server-Side Rendering
>> Styling Approach
>> Community
Remix vs. Next.js
Remix vs. Gatsby
Creating a New Remix Project
Building a Todo Application

The Benefits of Using Remix

In this section, we will talk about the benefits of using Remix.

Faster Data Fetching

Every framework boasts faster data fetching, but Remix takes that one step further. Instead of the traditional way of fetching data through components via a series of requests, Remix loads data in parallel on the server. It sends back a ready-to-be-displayed HTML document that contains the data.

Routing

Remix boasts about the community and the team behind React Router v6; with this, Remix works with React APIs. Remix also uses a file system to define page routes.

Nested Pages

One feature that Remix brings is nested routes. This allows Remix to only load routes that change or make updates to a nested component. Nested routes mean that you can have a parent component control the rendering of a child component. 

Error Handling

Remix automatically catches any error thrown from an action, component, or loader. Instead of rendering the component and having an error flag on the screen, Remix will render the component’s error boundary instead. 

Error boundaries are components that catch errors, log them and render a fallback UI instead. This leads to a better user experience in the application.

The Drawbacks of Choosing Remix for Web Apps

Remix has lots of benefits, but some drawbacks come with using it. This section will talk about the cons of using and choosing Remix for building web applications.

Only Does Server-Side Rendering

In recent times, Jamstack applications that use SSG (static site generation) have become prevalent and are also fast. Static site generation is the process of building sites that render at build time. They make it easy to deploy but aren’t great for dynamic data.

This is one drawback that comes with using Remix. It sacrifices some speed because it doesn’t use SSG, and also makes development complex. 

Styling Approach

Another problem with Remix is its approach to styling. Most styling frameworks aren’t supported yet, and we don’t know when they might be. Remix also offers a built-in way of linking CSS style sheets with the link tag.

Community

Remix has been in use since 2020, but recently the developers changed their business package and made it accessible and open source. However, it’s important to note that the Remix community is still in its early stages, and you might not encounter issues with the framework in its genesis.

Remix vs. Next.js

There are many similarities between Remix and Next.js. Both are similar in terms of routing. These are also server-side rendered frameworks. Below are some differences between RemixRemix and Next.js.

  • Remix only comes with SSR, which helps with dynamic data, while Next.js comes with static site generation (SSG).
  • Remix comes with out-of-the-box support for cookies and sessions, while Next.js does not offer support for this; however, there are open source libraries for these functionalities.

Remix vs. Gatsby

Gatsby is an open-source React framework for building static applications. Gatsby comes with GraphQL and webpack out of the box. Remix and Gatsby are React frameworks that are built for speed, however, below are some differences between the frameworks.

  • Hot reload: Hot reload of code comes out of the box with Gatsby while Remix doesn’t offer support for this, however, there are packages for this.
  • Gatsby only serves static files and data, while Remix is great for managing dynamic and ever-changing files and data.

Creating a New Remix Project

To create a new Remix app, navigate to the folder of your choice and run the command below:

npx [email protected] 

You will be required to pick a name for your app and your location for deploying the application. Our demo application won’t require deployment so you can select any deployment target. The next choice is to choose between Javascript and Typescript. I will use Javascript, but you can select the one you are most comfortable with. Next, choose yes when prompted if you want to run npm install.

A brief look at the files and folders for the Remix app

  • The app/ folder is where your code lives.
  • The app/entry.client.tsx file is what runs first when in the browser and is also used for hydrating the React components.
  • The app/entry.server.tsx file is for the server and will generate an HTTP response for server-side rendering. The app/entry.server.tsx and app/entry.client.tsx serves as entry files and is managed by Remix.
  • The public/ file holds static files for the application.

Building a Todo Application

Every new Remix app comes with some how-to tutorials and demos from RemixRemix built into it. We will do a little clean-up and delete the CSS file content and any demo folder that you may find. Navigate to the index.jsx file and delete all boilerplate code. Now copy the code below and paste it there.

export default function Index() {
  return <h1>Todo Application</h1>;
}

The code above is the application’s starting point and shows the similarities between Remix and React in terms of syntax. Please copy the code below and paste it into the index.jsx file. We will get into what it does in a moment.

import { useState } from 'react';
import { RiDeleteBin5Line } from 'react-icons/ri';
import Add from '../component/Add';
import styles from '../styles/task.css';
export const links = () => {
  return [{ rel: 'stylesheet', href: styles }];
};
export default function Index() {
  const [AddSection, setAddSection] = useState(false);
  const [tasks, setTasks] = useState([
    { id: 1, task: 'First task', description: 'Description 1', time: '1:00' },
    { id: 2, task: 'Second task', description: 'Description 2', time: '2:00' },
  ]);
  // Add task
  const addTask = (task) => {
    const id = Math.floor(Math.random() * 10000) + 1;
    const newTask = { id, ...task };
    setTasks([...tasks, newTask]);
  };
  // Delete task
  const deleteTask = (id) => {
    setTasks(tasks.filter((tasks) => tasks.id !== id));
  };
  // Toggle add section
  const toggleShow = () => {
    setAddSection(!AddSection);
  };
  return (
    <div className="container">
      <header className="header">
        <h1>Todo Application</h1>
        <button
          className="btn"
          style={
            AddSection
              ? { backgroundColor: 'red' }
              : { backgroundColor: 'green' }
          }
          onClick={toggleShow}
        >
          {AddSection ? 'Close' : 'Add'}
        </button>
      </header>
      {AddSection && <Add onAdd={addTask} />}
      {tasks.length > 0 ? (
        <div className="task-section">
          {tasks.map((task) => (
            <div className="task" key={task.id}>
              <h3 className="task-title">{task.task}</h3>
              <p className="task-description">{task.description}</p>
              <p className="task-time">{task.time}</p>
              <button
                className="delete-icon"
                onClick={() => deleteTask(task.id)}
              >
                <RiDeleteBin5Line />
              </button>
            </div>
          ))}
        </div>
      ) : (
        <h1>No Task</h1>
      )}
    </div>
  );
}

In the code above, we first imported useState to manage the application’s state. After that, we imported the component that handles the addition of tasks to the todo application. Next, we imported the stylesheets for the application. In the first few lines, we see no differences between the syntax of Remix and that of React.

import styles from '../styles/task.css';
export const links = () => {
  return [{ rel: 'stylesheet', href: styles }];
};

Remember when we spoke on one of the drawbacks of using RemixRemix as a styling approach. In the code block above, we encounter a unique export. To use the style sheet in RemixRemix, you first import it and then use that unique export:

const [AddSection, setAddSection] = useState(false);
  const [tasks, setTasks] = useState([
    { id: 1, task: 'First task', description: 'Description 1', time: '1:00' },
    { id: 2, task: 'Second task', description: 'Description 2', time: '2:00' },
  ]);

  // Add task
  const addTask = (task) => {
    const id = Math.floor(Math.random() * 10000) + 1;
    const newTask = { id, ...task };
    setTasks([...tasks, newTask]);
  };
  // Delete task
  const deleteTask = (id) => {
    setTasks(tasks.filter((tasks) => tasks.id !== id));
  };
  // Toggle add section
  const toggleShow = () => {
    setAddSection(!AddSection);
  };

In the code block above, we set the state events for the application. We also added functionalities for adding new tasks, deleting completed tasks, and toggling the button that reveals the form for adding new tasks.

import { useState } from 'react';
export default function Add({ onAdd }) {
  const [task, setTask] = useState('');
  const [description, setDescription] = useState('');
  const [time, setTime] = useState('');
  const submit = (e) => {
    e.preventDefault();
    if (!task || !time) {
      alert("You can't submit an empty task or time!");
      return;
    }
    onAdd({ task, description, time });
    setTask('');
    setDescription('');
    setTime('');
  };
  return (
    <div>
      <h2>Add Task</h2>
      <form className="add-form">
        <div className="form-control">
          <label>Task</label>
          <input
            type="text"
            value={task}
            placeholder="Add Task"
            onChange={(e) => setTask(e.target.value)}
          />
        </div>
        <div className="form-control">
          <label>Description</label>
          <input
            type="text"
            value={description}
            placeholder="Description"
            onChange={(e) => setDescription(e.target.value)}
          />
        </div>
        <div className="form-control">
          <label>Set Day & Time</label>
          <input
            type="text"
            value={time}
            placeholder="Day & Time"
            onChange={(e) => setTime(e.target.value)}
          />
        </div>
        <button className="btn btn-block" onClick={submit}>
          Save task
        </button>
      </form>
    </div>
  );
}

The code block is the component that handles the addition of tasks to the todo application. First, we set the state events of the input. Next, we added the functionality for the submission which we passed to the props coming from the Index.jsx file.

Copy and paste the code below into your created style sheet for styling:

@import url('https://fonts.googleapis.com/css2?family=Poppins:[email protected];400&display=swap');
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  font-size: 16px;
}
body {
  font-family: 'Poppins', sans-serif;
}
.container {
  margin: 3rem auto 2rem auto;
  overflow: auto;
  min-height: 25rem;
  border: 0;
  padding: 2rem;
  width: 80%;
  border-radius: 0.325rem;
}
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.2rem;
}
.btn{
  border: 0;
  border-radius: 0.325rem;
  color: #000;
  cursor: pointer;
  font-size: 1.2rem;
  font-weight: 600;
  padding: 0.5rem 1.5rem;
  transition: all 0.2s ease-in-out;
}
.task {
  background: #dbdbdb;
  border-radius: 3px;
  margin: 0.255rem;
  padding: 0.625rem 1.2rem;
  cursor: pointer;
}
.task h3 {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.time {
  color: #4e4e4e;
}
.task-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.task-time {
  color: #4e4e4e;
}
.delete-icon {
  color: black;
  cursor: pointer;
  right: 1rem;
  font-size: 1.625rem;
  top: 35%;
  outline: none;
}
.delete-icon:hover {
  color: #f11;
}
.add-form {
  margin-bottom: 2.325rem;
}
.form-control {
  margin: 1.2rem 0;
}
.form-control label {
  display: block;
}
.form-control input {
  width: 100%;
  height: 2.325rem;
  margin: 0.25rem;
  padding: 0.2rem 0.35rem;
  font-size: 1.125rem;
}
.form-control-check {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.form-control-check label {
  flex: 1;
}
.form-control-check input {
  flex: 2;
  height: 1.25rem;
}

Conclusion

Remix is a robust, fast, server-side rendering framework with capabilities for becoming one of the most used frameworks in the future. There are some significant drawbacks to using it, but they shouldn’t detract from the benefits of Remix. In this article, we learned about RemixRemix and its usefulness in building web apps in this article.