Learning React: Creating a Roll a Dice App - R1
Tags: tutorial, programming, beginners, react
Published: 2024-06-18 12:47:21

It's not too late to learn react so, here is my journey. I will try to post everyday about the progress I made. I tried to learn react last year but was not able to finish it and now I'm again a noob. 

So, this is my 2nd shot in learning react. Haven't touched the basics of it but instead I will try to learn it by building some projects.

The first project I build is Roll a Dice. This is a very simple one and gave a good idea of how the file structure works and everything to the base level in react. Also, I'm using next.js to build this small web application. I just want to be comfortable with both of these things at the same time that's why.

## What I learn

- React.js and Next.js file structure
- Running and creating a react application
- Some jsx
- HTML and CSS in react
- useState Hook
- and other basic stuff

Now, let's build.

## Roll a Dice Web App in React.js and Next.js

### Create repo

This is not necessary but it's an good idea to keep everything in Github repo for various needs. But mine is to have some commits everyday on my profile and learn every system that I need to accomplish in real world job. 

I just then cloned that repo in my system. Opened the terminal, cd into project directory.

### Creating the project

Since, I'm using Next.js so, the command to create the project will be:

`npx create-next-app@latest .`

`.` in the end so, it won't create another directory in the project project folder and take base directory name as it is.

You can then select your preferred configuration like JS or TS. I'm using JS, for tailwind say no. Since it's a very small project we don't need that.

After completion of the installation. Run the command to test if it's working.

`npm run dev`

Visit localhost:3000, you should see the vercel/next.js landing page.

If upto this point if everything is working fine. Congratulations, we have now learned how to create a react project using next.js.

### Clean up the files

The next step is to clean some files and remove the unwanted code from our project.

You can read about the [project structure here](https://nextjs.org/docs/getting-started/project-structure), I won't talk about this here. 

Remove everything except the page.js and layout.js from the src/app directory. 

#### layout.js
The default code should look like this:

```
import { Inter } from "next/font/google";
import "./globals.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}

```
We're going to remove some of it and keep and add what we need for this project.

Remove the second `import` of CSS or just rename it to `style.css`. We can keep the fonts. Next we have export metadata. We're going to change it instead of removing to 

```
export const metadata = {
  title: "Roll a Dice",
  description: "A simple roll a dice web app!",
};
```

Next keep the remaining Root function. The end code of the file should look like this:

```
import { Inter } from "next/font/google";
import "./style.css";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Roll a Dice",
  description: "A simple roll a dice web app!",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  );
}
```

Next, create a `style.css` file under the same directory `src/app`, because we need one style file and we imported it on the top of layout.js file.

#### page.js
In this file, let's remove everything and write from the beginning. Let's first have a function to render our homepage with a simple heading text.

```
export default function Home() {
  return (
    <main className="page">
      <h1>Roll a Dice</h1>
    </main>
  );
}
```
In this code, we have a simple react function which returns a simple `h1` in our application.

Next, we need the dice image and a button to roll it. We want the image to randomly change to another one upon clicking that button.

#### Images

Before that let's collect some images for the dice. I have already downloaded them from the web. So, you can copy these [6 images from the repo](https://github.com/IVEWOR/roll-dice/tree/main/public). Store them in the public folder. Make sure it is present in the root directory, same level as `src` directory.

```
- roll-dice
-- src/app
-- public/all-your-images.png
```

Make sure the dice images are named like this:
```
dice-1.png
dice-2.png
...
dice-6.png
```

You can name it whatever you want just please adjust it accordingly in the code.

#### page.js

Now, let's create an image and the button, which we talked earlier. For the image we need to import the `Image` component from next.js since we're using next.js.

```
import Image from "next/image";

export default function Home() {
  return (
    <main className="page">
      <div className="img-side">
        <Image src="/dice-1.png" width="400" height="400" />
      </div>

      <div className={"text-side"}>
        <h1>Roll a Dice</h1>
        <p>
          Roll a Dice is a user-friendly web app that simulates dice rolls.
          Perfect for games or decision-making, it offers quick, random results
          with a single click.
        </p>
        <button>Roll the dice</button>
      </div>
    </main>
  );
}
```

Now, our web app looks like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztiu6fxlqthvb18232qo.png)

#### style.css
Let's add some styling to it. I won't talk about this much. Here's the CSS:

```
body {
  background-color: #f0f0f0;
  padding: 10px;
}

body,
* {
  margin: 0;
}

.page {
  max-width: 850px;
  padding: 20px;
  margin: 0 auto;
  background-color: #fff;
  border-radius: 28px;
  display: grid;
  gap: 20px;
  align-items: center;
}

.img-side img {
  width: 350px;
  height: auto;
  max-width: 100%;
}

.text-side h1 {
  margin-bottom: 10px;
}

.text-side button {
  padding: 12px 28px;
  line-height: 1;
  border: solid 2px #222;
  background-color: #222;
  color: #fff;
  font-size: 17px;
  letter-spacing: 0.5px;
  border-radius: 18px;
  margin-top: 30px;
  cursor: pointer;
  transition: cubic-bezier(0.6, -0.28, 0.735, 0.045) 0.2s all;
}

.text-side button:hover {
  opacity: 0.9;
}

@media (min-width: 850px) {
  .page {
    grid-template-columns: 1fr 1fr;
  }
}
```

Now, the web app looks like this:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gawj9gbe8jnhi7zz3py2.png)

#### Adding the functionality

Again in `page.js`, we're going to import a useState which an react hook using `import { useState } from "react";`. First let's do the destructuring and initialize the variable with 1.

```
import Image from "next/image";
import { useState } from "react";

export default function Home() {

const [num, setNum] = useState(1);
```

Then we're going to create random number generator function inside our `Home` function, which is going to return a number from 1 to 6.  

```
import Image from "next/image";
import { useState } from "react";

export default function Home() {

  const [num, setNum] = useState(1);

  const randomNumberInRange = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }


....rest of the code
```

Now, we need a function that fires our `randomNumberInRange` function.

```
import Image from "next/image";
import { useState } from "react";

export default function Home() {
  const [num, setNum] = useState(1);

  const randomNumberInRange = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  };

  const handleClick = () => {
    setNum(randomNumberInRange(1, 6));
  };

  return (

....rest of the code
```

Now, we have to assign the `handleClick` function to the button. So, it works on click. Let's do that:

```
<button onClick={handleClick}>Roll the dice</button>
```

We're mostly done with our web app. We just need to make some adjustments in the `Image` tag so, it can use the random `num` from our function. To do that, modify the `Image` `src` to `<Image src={"/dice-" + num + ".png"} width="400" height="400" />`.

Now, the `page.js` code should look like this:

```
"use client";

import Image from "next/image";
import { useState } from "react";

export default function Home() {
  const [num, setNum] = useState(1);

  const randomNumberInRange = (min, max) => {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  };

  const handleClick = () => {
    setNum(randomNumberInRange(1, 6));
  };

  return (
    <main className="page">
      <div className="img-side">
        <Image src={"/dice-" + num + ".png"} width="400" height="400" />
      </div>

      <div className={"text-side"}>
        <h1>Roll a Dice</h1>
        <p>
          Roll a Dice is a user-friendly web app that simulates dice rolls.
          Perfect for games or decision-making, it offers quick, random results
          with a single click.
        </p>
        <button onClick={handleClick}>Roll the dice</button>
      </div>
    </main>
  );
}
```

Now, if you click on the button. The image should start changing like rolling a dice.

And that's it for this web app, atleast for now.

If you have any suggestions or feedback, then please share! [The repo is here](https://github.com/IVEWOR/roll-dice)