React with Typescript
Tags: webdev, react, typescript, beginners
Published: 2021-10-19 07:58:29

At present react js has been a very popular library to build beautiful and scalable user interfaces. Today I would like to build a demo react project with typescript.

###Project setup
We would like to use the `create-react-app` environment built by facebook developer team to create our project. Our project will have a form to add favorite tv series and show the list. It will be a single page website. At first we will run the following command
```
npx create-react-app --template typescript fav-tv-series
cd fav-tv-series
npm run start
``` 
The first command will create a react app named `fav-tv-series` having typescript template. Then after going to that directory we will run the third command which will create a process running on port number 3000 and look like this
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkdawy8q5lugx5uiskch.PNG)

###Creating Interface
In typescript our main concern will be defining strict type to every data that will be used. `interface` is a pretty good way to define a data and use that as a type in ts. In the `src` folder of the root folder we will create a directory named `interfaces` and inside it we will create a file named `SeriesProps.tsx`. Here we will create an interface named `SeriesProps` like following
```
export interface SeriesProps {
    seriesList: {
        name: string;
        imdb: number;
        cover: string;
        seasons: number;
        genre: string;
      }[]
}
```
###Updating App
At first we will update the existing `App.tsx` file by removing the existing code. Our single page web application will contain two components. One is a form where a user will give necessary inputs about his favourite series and another is a list containing those serieses. The data will be stored in a state named `seriesList` and updated with the help of `setSeriesList` method.
```
import React, { useState } from 'react';
import { SeriesProps } from './interfaces/SeriesProps';
import './App.css';
import List from './components/List';
import Form from './components/Form';

function App() {
  const [seriesList, setSeriesList] = useState<SeriesProps["seriesList"]>([]);

  return (
    <div className="App">
      <h1>My Favourite TV Series</h1>
      <Form seriesList={seriesList} setSeriesList={setSeriesList} />
      <List seriesList={seriesList} />
    </div>
  );
}

export default App;

```

###Creating List
In `src` directory of root folder we will create a directory named `components` and there we will create the `List.tsx` file. Our component will look like below
```
import React, { FC } from "react";
import { SeriesProps } from "../interfaces/SeriesProps";

const List:FC<SeriesProps> = ({seriesList}) => (
    <div className="series-list">
        {seriesList.map((series) => (
            <div className="series-item">
                <img src={series.cover} alt="Series-cover" />
                <p><b>{series.name}</b></p>
                <p>{series.genre}</p> 
                <p>{series.seasons} seasons</p>
                <p>★★★★★ {series.imdb}</p>
            </div>
        ))}
    </div>
);

export default List;
```
Here we can have a look at `FC` which means Functional Component and it guides us with types. Here we have passed `SeriesProps` as props and finally we have used [map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) function to render tv series list.

###Creating Form
Now we are left with creating the form element where we will give necessary inputs. Here we will use [controlled components](https://reactjs.org/docs/forms.html) to build input elements. For simplicity we will create a state object where the necessary input values will be kept. We will use `useState` for this.
```
const [input, setInput] = useState({
        name: "",
        genre: "",
        cover: "",
        imdb: 0,
        seasons: 0
    });
```
Now we will render the components. Here we will have five input fields having three text and two number type inputs.
```
return (
        <div className="form-container">
            <div className="form-div">
                <label htmlFor="name">Name</label>
                <input type="text" name="name" id="name" value={input.name} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="genre">Genre</label>
                <input type="text" name="genre" id="genre" value={input.genre} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="cover">Cover Link</label>
                <input type="text" name="cover" id="cover" value={input.cover} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="imdb">IMDB Rating</label>
                <input type="number" name="imdb" id="imdb" value={input.imdb} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="seasons">Total Seasons</label>
                <input type="number" name="seasons" id="seasons" value={input.seasons} onChange={handleChange} />
            </div>
            <button type="button" onClick={handleClick}>Add Series</button>
        </div>
    );
```
Here we can see that the value of each input field will be stored to the state object. We can see that all input fields have a function named `handleChange` which will be invoked as an `onChange` listener and the button has an `onClick` listener named `handleClick`. We will implement these two methods now. The handleChange method is quite straight forward. Here we destructure the `input` state and update the particular state element needed to be updated. One important thing to notice is that the type of event we are passing to that function. Here the type is `ChangeEvent<HTMLInputElement>` which means our handleChange method will only accept html input element change event. One thing to notice is that we have kept the name and value of each input same for which we can use `[name]: value` statement.
```
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { value, name } = e.target;
        setInput({
            ...input,
            [name]: value
        });
    };
```
Before implementing the handleClick method we need to define a props which will be used to update and store the series list. As we have already defined a state in our `App.tsx` using `useState`, we need to pass those in this `Form` component and use in our handleClick method. Lets have a look at the following interface.
```
interface Props {
    seriesList: SeriesProps["seriesList"],
    setSeriesList: Dispatch<SetStateAction<SeriesProps["seriesList"]>>
}
```
Now we will implement our handleClick method.
```
const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
        const { name, genre, cover, imdb, seasons } = input;
        if(!name && !genre && !cover && !imdb && !seasons) return;
        const series = { name, genre, cover, imdb, seasons };
        setSeriesList([...seriesList, series]);
        setInput({
            name: "",
            genre: "",
            cover: "",
            imdb: 0,
            seasons: 0
        });
    };
```
Our method only accepts a mouse event coming from an html button element. At first we have destructured our input state. Then we have checked whether any input field is empty. If so then we won't move further. Otherwise we have created a series object and appended it to the series list. After that we have made all fields empty. So our complete `Form.tsx` looks like this
```
import React, { FC, useState, ChangeEvent, MouseEvent, Dispatch, SetStateAction } from "react";
import { SeriesProps } from "../interfaces/SeriesProps";

interface Props {
    seriesList: SeriesProps["seriesList"],
    setSeriesList: Dispatch<SetStateAction<SeriesProps["seriesList"]>>
}

const Form: FC<Props> = ({ seriesList, setSeriesList }) => {

    const [input, setInput] = useState({
        name: "",
        genre: "",
        cover: "",
        imdb: 0,
        seasons: 0
    });

    const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { value, name } = e.target;
        setInput({
            ...input,
            [name]: value
        });
    };

    const handleClick = (e: MouseEvent<HTMLButtonElement>) => {
        const { name, genre, cover, imdb, seasons } = input;
        const series = { name, genre, cover, imdb, seasons };
        if(!name && !genre && !cover && !imdb && !seasons) return;
        setSeriesList([...seriesList, series]);
        setInput({
            name: "",
            genre: "",
            cover: "",
            imdb: 0,
            seasons: 0
        });
    };

    return (
        <div className="form-container">
            <div className="form-div">
                <label htmlFor="name">Name</label>
                <input type="text" name="name" id="name" value={input.name} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="genre">Genre</label>
                <input type="text" name="genre" id="genre" value={input.genre} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="cover">Cover Link</label>
                <input type="text" name="cover" id="cover" value={input.cover} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="imdb">IMDB Rating</label>
                <input type="number" name="imdb" id="imdb" value={input.imdb} onChange={handleChange} />
            </div>
            <div className="form-div">
                <label htmlFor="seasons">Total Seasons</label>
                <input type="number" name="seasons" id="seasons" value={input.seasons} onChange={handleChange} />
            </div>
            <button type="button" onClick={handleClick}>Add Series</button>
        </div>
    );
};

export default Form;
``` 
Now we are only left with adding css styles. For simplicity we have made change only in the `App.css` files which looks like
```
.form-container {
  width: 400px;
  margin: auto;
}

h1 {
  text-align: center;
}

.form-div {
  margin-bottom: 10px;
}

input[type='text'],
input[type='number'] {
  float: right;
  width: 70%;
  padding: 3px;
}

input[type='checkbox'] {
  margin-left: 110px;
}

button {
  margin: 10px 0;
  padding: 10px 0;
  width: 100%;
  cursor: pointer;
  font-weight: bold;
  text-transform: uppercase;
  font-size: 16px;
}

p {
  line-height: 5px;
}

.series-list {
  display: flex;
  flex-flow: wrap;
  margin: 50px auto;
  width: 90%;
}

.series-item {
  padding: 0 20px 20px 0;
  width: 300px;
}
```
After we are finished with all coding, we can have a look at our browser's http://localhost:3000/ link. After adding some data it should look like following
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j6tbsdnr8ux7kkfdjjj9.PNG)
The whole project is in github. You can very well have a look in it [here](https://github.com/alim1496/react-with-typescript).

Happy Coding 😀😀😀😀😀

<a href="https://www.buymeacoffee.com/alim1496" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>