Building a React Application with Vite
Tags: javascript, webdev, react, vite
Published: 2022-05-21 21:04:17


by [Clara Ekekenta](https://blog.openreplay.com/authors/clara-ekekenta)

Vite is the next-generation front-end build tool that provides a faster and leaner development experience for current web projects. It consists of two major parts:

- A development server that provides [rich feature enhancements](https://vitejs.dev/guide/features.html) over [native ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), for example, extremely fast [Hot Module Replacement (HMR)](https://vitejs.dev/guide/features.html#hot-module-replacement).

- A build command that bundles your code with [Rollup](https://rollupjs.org/), preconfigured to output highly optimized static assets for production.

It also supports preconfigured Rollup builds with multi-page and library mode support, a Rollup-superset plugin interface shared between dev and build flexible programmatic APIs with TypeScript typing, and on-demand file serving over native ESM. Vite is opinionated and comes with sensible defaults out of the box, but is also highly extensible via its [Plugin API](https://vitejs.dev/guide/api-plugin.html) and [JavaScript API](https://vitejs.dev/guide/api-javascript.html) with full typing support.

In this tutorial, you'll learn how to build a React application with Vite. We'll create a blog application for the demonstrations. You need to have [Node.js](https://nodejs.org/en/) version > = 12.2.0 is installed. However, some templates require a higher Node.js version to work. Please upgrade if your package manager warns you about it. The code for this tutorial is available [here](https://github.com/Claradev32/Vite-Blog-App) on Github. Feel free to clone and follow along. Without more ado, let's get started!

## Scaffold a Vite Application

To get started, you need to scaffold a Vite project with the command below:

```
npm create vite@latest
```

The above command will prompt you to select your project name and framework. We'll use the default name for demonstration by pressing the enter key, selecting "react" as the framework, and "react-ts" as the variable to enable Typescript support. Your selection should look like the screenshot below:

![Scaffold application](https://blog.openreplay.com/static/12adb8802bfb7e366f4ddef62208801d/ae386/image01.png)

Now let's look at the project structure for our application. After running the create command, Vite will generate the following folder structure as shown below:

```
vite-project
┣ src
┃ ┣ App.css
┃ ┣ App.tsx
┃ ┣ favicon.svg
┃ ┣ index.css
┃ ┣ logo.svg
┃ ┣ main.tsx
┃ ┗ vite-env.d.ts
┣ .gitignore
┣ index.html
┣ package.json
┣ tsconfig.json
┣ tsconfig.node.json
┗ vite.config.ts
```

Let's look at the essential files that may look strange to you.

- `index.htm`: This is the central file, usually located in a `public` folder in a typical reacted application.
- `main.tsx:` This is where the code responsible for the browser output is rendered. A React application is usually named `index.ts` or `index.js.`
- `vite.config.json`: This is the configuration file for every Vite project. If you open the file, you'll discover that React has been added as a plugin in the plugins array.

## Create our Blog Component

Now let's start building our blog application by creating a blog component. Create a `component` folder in the `src` folder and create a`Blog.tsx` then add the code snippet below:

```javascript
import BlogList from "./BlogList";
export default function Blog() {
  return (
    <div className="container">
      <div className="content">
        <ul>
          <BlogList />
        </ul>
      </div>
    </div>
  );
}
```

In the above code snippet, we've created the blog and imported the `BlogList` component, which we'll create in the next section to display the list of all the blogs in our application. Now update the code in the `App.tsx` file with code snippets below:

```javascript
import "./App.css";
import Blog from "./components/Blog";

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <div className="main">
          <div className="search">
            <input type="text" placeholder="Search a blog"></input>
          </div>
          <button>Add New</button>
        </div>
      </header>
      <Blog />
    </div>
  );
}

export default App;
```

In the code snippet, we imported our `Blog` component and the `App.css` file, then rendered the `Blog` component. Copy the styles for the application here and replace the CSS styles in the `App.css` file.

## Create the BlogList component

To display the list of all the blogs created by the users, let's create a `BlogList.tsx` file in the component folder and add the code snippets below:

```
export default function BlogList() {
  return (
    <li>
      <div className="info">
        <h6>John Doe</h6>
        <small>May 3 2022</small>
      </div>
      <p>Build a REST API with Typescript and Node.js</p>
    </li>
  );
}
```

Now start the server with the command below:

```
npm run dev
```

Then open your browser and navigate to `http://localhost:3000/`; you should see an output like the one on the screenshot below:

![Blog page](https://blog.openreplay.com/static/4fcfa7833511a8e500f5ade191db4708/75494/image02.png)

## Create Todo Service

So far our application is only displaying a hardcoded blog. Now let's create a `BlogData` service to add blogs and display blogs dynamically in our application. Create a `service` folder in the `component` directory, create a `BlogData.ts` file and add the code snippets below:

```javascript
import IBlog from "./interface";
export const genBlogId = (): string => Math.random().toString(36).slice(-6);

export const BlogData: IBlog[] = [
  {
    id: genBlogId(),
    title: "Build a REST API with Typescript and Node.js",
    cover:
      "https://www.freecodecamp.org/news/content/images/size/w2000/2020/02/typescript.png",
    body: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Odio esse nesciunt ab nulla facere adipisci magnam quos provident! Nam, dolor aut sunt ab expedita minus quae repellendus iure fuga perspiciatis? Lorem ipsum dolor sit amet consectetur adipisicing elit. Neque voluptates, obcaecati quod officiis a fuga, alias laborum quisquam eius, ullam et iure corporis assumenda dolores porro! Molestiae, magnam fuga! Voluptatum?",
    description:
      "This is a comprehensive tutorial on how to build a REST backend with Typescript and Node.js",
    dateCreated: new Date(Date.now()).toString().substr(4, 11),
    createdBy: "John Doe",
  },
];
```

In the above code snippet, we imported the `IBlog` interface, which we'll be creating shortly to define an interface for our blogs. Then we created a `genBlogId` function to generate a random `id` for all the blogs created. Finally, we made a `BlogData` array with some blog data.
Now let's go ahead and create the `IBlog` interface. create an `interface` folder in the `service` directory, create an `index.ts` file and add the code snippet below:

```javascript
export default interface IBlog {
  id: string;
  title: string;
  cover: string;
  body: string;
  description: string;
  createdBy: string;
  dateCreated: string;
}
```

## Create Blog Details component

With the `Blog` and `BlogList` component created, let's create another component to view the details our every blog in our application. Create a `BlogDetails.tsx` file in the component folder and add the code snippet below:

```javascript
import { useParams } from "react-router-dom";
import { BlogData } from "./service/BlogData";

export default function BlogDetails() {
  const { id } = useParams();
  const data = BlogData.filter((data) => data.id === id);
  console.log(data);
  return (
    <div className="container">
      <div className="content">
        <ul>
          <li>
            <div className="info">
              <h6>{data[0].createdBy}</h6>
              <small>{data[0].dateCreated}</small>
            </div>

            <p>{data[0].title}</p>
            <img src={data[0].cover} />
            <p className="body">{data[0].body}</p>
          </li>
        </ul>
      </div>
    </div>
  );
}
```

In the above code snippet, we imported the `BlogData` array and `useParams` hook from `react-router-dom`, which we'll set up in the next section to get the blog's id from the URL.
Then we used the Javascript filter to get the blog the given from our URL and display the details.


## Open Source Session Replay

_[OpenReplay](https://github.com/openreplay/openreplay) is an open-source alternative to FullStory and LogRocket. It gives you full observability by replaying everything your users do on your app and showing how your stack behaves for every issue. OpenReplay is self-hosted for full control over your data._

![replayer.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1647097041609/Qi6sMOaaB.png)

_Happy debugging for modern frontend teams - [start monitoring your web app for free](https://github.com/openreplay/openreplay)._



## Setup Routes and Display Blogs

Now let's add routing to our application using `react-router-dom` and display our blog data. But, first, we need to install `react-router-dom` with the command below:

```
npm install react-router-dom
```
    
Then update the `App.tsx` file with the code snippet below to add our routes.

```javascript
// ...
import {
  BrowserRouter as Router,
  Routes,
  Route
} from "react-router-dom";
// ...
return (
   ...
   </header>
     <Router>
        <Routes>
          <Route path="/" element={<Blog />} />
          <Route path="/:id" element={<BlogDetails />} />
        </Routes>
      </Router>
    ...
  )
```

In the above code snippet, we created the routes for our application. The `Blog` component will be routed when a user visits our application, and then we can use the pass in the blog's `id` as props to the URL to view the details of that blog. Update the code in the `BlogList` component with the code snippet below:

```javascript
import IBlog from "./service/interface";
import { Link } from "react-router-dom";

export default function BlogList(props: { data: IBlog }) {
  const { data } = props;
  return (
    <li>
      <div className="info">
        <h6>{data.createdBy}</h6>
        <small>{data.dateCreated}</small>
      </div>

      <Link to={`/${data.id}`}>
        <p>{data.title}</p>
      </Link>
    </li>
  );
}
```

We have displayed our blog data here, which we'll accept as props from the `Blog` component. Also, to make the data showing the `BlogDetails` component dynamic, we created a link and passed the id of each blog to the request parameter.
Finally, import and then display the data from our `BlogData` service in the `Blog` component with the code snippet below:

```javascript
import IBlog from "./service/interface";
import { BlogData } from "./service/BlogData";

return (
...
    <ul>
          {BlogData.map((data: IBlog) => (
            <BlogList key={data.id} data={data} />
          ))}
    </ul>
...
)
```

If you go back to your browser, things should look slightly different. You can now view the details of the blogs by clicking the link.

![Viewing details](https://blog.openreplay.com/static/a3a28cd8ee2edd7fac91b4725f32058e/e3533/image03.png)

## Create the Modal component

At this point, we can view our blog details. Let's add a modal to enable the user to add new blogs. Create a `Model.tsx` file in the component folder and add the code snippet below:

```javascript
import { useState } from "react";
import { BlogData, genBlogId } from "./service/BlogData";

export default function Modal(props: { showModal: any, setShowModal: any }) {
  const { showModal, setShowModal } = props;
  const [title, setTitle] = useState("");
  const [coverUrl, setCoverURL] = useState("");
  const [body, setBody] = useState("");
  const [description, setDescription] = useState("");
  const [createdBy, setCreatedBy] = useState("");

  return (
    <div>
      <div className="Modal" style={{ display: showModal ? "block" : "none" }}>
        <span className="close" onClick={handleCloseModal}>
          X
        </span>
        <div className="form-container">
          <form onSubmit={handleSubmit}>
            <input
              type="text"
              placeholder="Title"
              name="name"
              onChange={(e) => setTitle(e.target.value)}
            ></input>
            <input
              type="text"
              placeholder="Cover URL"
              name="coverUrl"
              onChange={(e) => setCoverURL(e.target.value)}
            ></input>
            <textarea
              name="body"
              id=""
              placeholder="Write something ..."
              rows={20}
              onChange={(e) => setBody(e.target.value)}
            ></textarea>
            <input
              type="text"
              placeholder="description"
              name="description"
              onChange={(e) => setDescription(e.target.value)}
            ></input>
            <input
              type="text"
              placeholder="createdBy"
              name="createdBy"
              onChange={(e) => setCreatedBy(e.target.value)}
            ></input>
            <button>Save</button>
          </form>
        </div>
      </div>
    </div>
  );
}
}
```

We import the `BlogData` array and the `genBlodId` function in the code snippet. We created a form to allow users to post blogs, and we defined the state variables for the fields in our form to get the user's inputs.
Now let's add methods to submit the blog and display the modal with the code snippets below:

```javascript
...
async function handleSubmit(event: {
  [x: string]: any;
  preventDefault: () => void;
}) {
  event.preventDefault();
  BlogData.push({
    id: genBlogId(),
    title,
    cover: coverUrl,
    body,
    description,
    createdBy,
    dateCreated: new Date(Date.now()).toString().substr(4, 11),
  });
  event.target.reset();
}

function handleCloseModal() {
  setShowModal(false);
}
...
```

Now import the `Modal` into our `App` component, add the state variables, and the method to close the modal. Your app component should look like the code snippets below:

```javascript
import { useState } from "react";
import "./App.css";
import Blog from "./components/Blog";
import BlogDetails from "./components/BlogDetails";
import Modal from "./components/Modal";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";

function App() {
  const [showModal, setShowModal] = useState(false);

  function handleOpenModal() {
    setShowModal(true);
  }

  return (
    <div className="App">
      <header className="App-header">
        <div className="main">
          <div className="search">
            <input type="text" placeholder="Search a blog"></input>
          </div>
          <button onClick={handleOpenModal}>Add New</button>
        </div>
      </header>
      <Router>
        <Routes>
          <Route path="/" element={<Blog />} />
          <Route path="/:id" element={<BlogDetails />} />
        </Routes>
      </Router>
      <Modal showModal={showModal} setShowModal={setShowModal} />
    </div>
  );
}
export default App;
```

Now you can click the `Add New` button to show the modal and post a new blog, as shown in the screenshot below:

![Click on Add new](https://blog.openreplay.com/static/5a419a67b019d850d0031ad95a230ad6/357da/image04.png)


We should have two blogs in our application; everything works!

![Everything works](https://blog.openreplay.com/static/5d9e51b22e85d28257d549841384a0fb/da42c/image05.png)


## Conclusion

Throughout this tutorial, you've learned how to build a React application with Vite. We started with a quick introduction to Vite and created a blog application for the demonstration. How would you use Vite in your next project after learning about Vite? Perhaps you can know more about [Vite](https://vitejs.dev/) and extend the features of this application.

[![newsletter](https://blog.openreplay.com/static/e6b18eda7a327511296a2f27692f9c70/e9957/newsletter.png)](https://newsletter.openreplay.com/)