DEV Community

Cover image for React and .NET Core 6.0 Sample Project with Docker - Part 2
Jayavardhan Reddy J
Jayavardhan Reddy J

Posted on • Updated on

React and .NET Core 6.0 Sample Project with Docker - Part 2

This article will explain how to create React Js application and consume ASP.NET Core Web API requests to fetch the movies data.
We will go through step by step with an example.

Please refer to my previous article to create ASP.NET Core Web API.

React and .NET Core 6.0 Sample Project with Docker -Part 1

The sections of this post will be as follows:

Creating a ReactJs project
Install packages
Add Components
Test the React UI Application

So, Let's get started.

Creating a ReactJs project:

Open Command Prompt and navigate to the path where you want to create the React app.

npx create-react-app movies-app

Image description

After creating the react project open the application using visual studio code.

Image description

Go to Terminal => start the react app

npm start

Once you start the project , the UI will be open in your default browser.

Image description

Install packages:

  • npm install semantic-ui-react semantic-ui-css

Image description

Open index.html page and past .css link in head section and .js after body section.

Image description

  • npm install axios

Image description

  • npm install react-toastify

Image description

Add Components

Go to => src => Create "Components" folder

  • Components => NavBar.jsx

This will add the navigation bar to the application.

import { Button, Menu } from "semantic-ui-react";
import "../index.css";

export default function NavBar(props) {
  return (
    <Menu inverted fixed="top">
      <Menu.Item header>
        <img
          src="/movieslogo.png"
          alt="logo"
          style={{ marginRight: "10px", marginLeft: "10px" }}
        />
        Movies
      </Menu.Item>
      <Menu.Item>
        <Button positive content="Add Movie" onClick={() => props.addForm()} />
      </Menu.Item>
    </Menu>
  );
}
Enter fullscreen mode Exit fullscreen mode
  • Components => MoviesTable.jsx

This component will display the table with movie details and actions to to delete and edit the movie.

import { Fragment } from "react";
import { Table, Button } from "semantic-ui-react";
import "../index.css";

export default function MoviesTable(props) {
  return (
    <Fragment>
      <h1 style={{ marginLeft: "30px" }}>Movies List</h1>
      <Table
        celled
        style={{
          marginLeft: "30px",
          marginTop: "30px",
          width: "1100px",
          border: "1px solid black",
        }}
      >
        <Table.Header>
          <Table.Row>
            <Table.HeaderCell>Title</Table.HeaderCell>
            <Table.HeaderCell>Language</Table.HeaderCell>
            <Table.HeaderCell>Year</Table.HeaderCell>
            <Table.HeaderCell>OTT</Table.HeaderCell>
            <Table.HeaderCell>Actions</Table.HeaderCell>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {props.movies.map((movie) => (
            <Table.Row key={movie.id}>
              <Table.Cell>{movie.title}</Table.Cell>
              <Table.Cell>{movie.movieLanguage}</Table.Cell>
              <Table.Cell>{movie.releaseYear}</Table.Cell>
              <Table.Cell>{movie.ott}</Table.Cell>
              <Table.Cell>
                <Button positive onClick={() => props.editForm(movie)}>
                  Edit
                </Button>
                <Button negative onClick={() => props.deleteMovie(movie.id)}>
                  {" "}
                  Delete
                </Button>
              </Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </Fragment>
  );
}

Enter fullscreen mode Exit fullscreen mode
  • Components => AddMovie.jsx

This component will be used to add the movie details to the database and display in movie table.

import { Button, Form, Segment } from "semantic-ui-react";
import React, { useState } from "react";
import { toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
export default function AddMovie(props) {

  const initialState = {
    title: "",
    movieLanguage: "",
    releaseYear: "",
    ott: "",
  };

  const [movie, setMovie] = useState(initialState);

  function handleSubmit(e) {
    e.preventDefault();
    if (!movie.title) {
      toast.error("Please fill all the details !", {
        position: toast.POSITION.TOP_RIGHT,
      });
      return;
    }
    props.handleSumbit(movie);
    setMovie(initialState);
  }

  function handleInputChange(event) {
    const { name, value } = event.target;
    setMovie({ ...movie, [name]: value });
  }

  return (
    <>
      <h1 style={{ marginLeft: "15px" }}>Add Movie</h1>
      <Segment clearing style={{ marginRight: "30px", marginTop: "30px", marginLeft: "10px" }} >
        <Form onSubmit={handleSubmit} autoComplete="off">
          <Form.Input placeholder="Title" value={movie.title} name="title" onChange={handleInputChange} />
          <Form.Input placeholder="Language" value={movie.movieLanguage} name="movieLanguage" onChange={handleInputChange}/>
          <Form.Input placeholder="Year" value={movie.releaseYear} name="releaseYear" onChange={handleInputChange} />
          <Form.Input placeholder="OTT" value={movie.ott} name="ott" onChange={handleInputChange}/>
          <Button floated="right" positive type="submit" content="Submit" />
          <Button floated="right" type="button" content="Cancel" onClick={() => props.closeForm()}
          />
        </Form>
      </Segment>
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode
  • Components => EditMove.jsx

This component will be used to edit the movie data and update.

import { Button, Form, Segment } from "semantic-ui-react";
import React, { useState } from "react";

export default function EditMovie(props) {
  const [movie, setMovie] = useState(props.movie);

  function handleSubmit(e) {
    e.preventDefault();
    props.handleEditMovie(movie);
  }

  function handleInputChange(event) {
    const { name, value } = event.target;
    setMovie({ ...movie, [name]: value });
  }

  return (
    <>
      <h1 style={{ marginLeft: "15px" }}>Edit Movie</h1>
      <Segment
        clearing
        style={{ marginRight: "30px", marginTop: "30px", marginLeft: "10px" }}
      >
        <Form onSubmit={handleSubmit} autoComplete="off">
          <Form.Input
            placeholder="Title"
            value={movie.title}
            name="title"
            onChange={handleInputChange}
          />

          <Form.Input
            placeholder="Language"
            value={movie.movieLanguage}
            name="movieLanguage"
            onChange={handleInputChange}
          />
          <Form.Input
            placeholder="Year"
            value={movie.releaseYear}
            name="releaseYear"
            onChange={handleInputChange}
          />

          <Form.Input
            placeholder="OTT"
            value={movie.ott}
            name="ott"
            onChange={handleInputChange}
          />
          <Form.TextArea
            placeholder="Description"
            value={movie.description}
            name="description"
            onChange={handleInputChange}
          />
          <Button floated="right" positive type="submit" content="Submit" />
          <Button
            floated="right"
            type="button"
            content="Cancel"
            onClick={() => props.closeForm()}
          />
        </Form>
      </Segment>
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode
  • Components => MoviesDashboard.jsx

This will be used to display the all movie related components.

import { Grid } from "semantic-ui-react";
import AddMovie from "./AddMovie";
import MoviesTable from "./MoviesTable";
import EditMovie from "./EditMovie";

export default function MoviesDashboard(props) {
  return (
    <Grid>
      <Grid.Column width="10">
        <MoviesTable movies={props.movies} editForm={props.editForm} deleteMovie={props.deleteMovie}/>
      </Grid.Column>
      <Grid.Column width="6">
        {props.showAddForm && (<AddMovie closeForm={props.closeForm} handleSumbit={props.handleSumbit} />)}
        {props.showEditForm && ( <EditMovie movie={props.movie} closeForm={props.closeForm} handleEditMovie={props.handleEditMovie} />  )}
      </Grid.Column>
    </Grid>
  );
}
Enter fullscreen mode Exit fullscreen mode

Update the App.js with the below code

import axios from "axios";
import "./App.css";
import { v4 as uuid } from "uuid";
import NavBar from "./components/NavBar";
import { useEffect, useState } from "react";
import MoviesDashboard from "./components/MoviesDashboard";
import { toast, ToastContainer } from "react-toastify";
function App() {
  const [movies, setMovies] = useState([]);
  const [movie, setMovie] = useState();
  const [showAddForm, setshowAddForm] = useState(false);
  const [showEditForm, setshowEditForm] = useState(false);

  useEffect(() => {
    axios.get("http://localhost:5159/api/movies").then((response) => {
      setMovies(response.data);
    });
  }, [movies]);

  function handleEditMovie(movie) {
    axios({
      method: "put",
      url: `http://localhost:5159/api/movies/${movie.id}`,
      data: {
        Id: movie.id,
        Title: movie.title,
        MovieLanguage: movie.movieLanguage,
        ReleaseYear: movie.releaseYear,
        OTT: movie.ott,
      },
      config: {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      },
    })
      .then((response) => {
        console.log(response);
        toast.success("Movie updated successfully", {
          position: toast.POSITION.TOP_RIGHT,
        });
      })
      .catch((error) => {
        console.log("the error has occured: " + error);
      });

    setMovies([...movies, movie]);
  }

  function handleSumbit(movie) {
    const data = {
      Id: uuid(),
      Title: movie.title,
      MovieLanguage: movie.movieLanguage,
      ReleaseYear: movie.releaseYear,
      OTT: movie.ott,
    };
    axios({
      method: "post",
      url: "http://localhost:5159/api/movies",
      data: data,
      config: {
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json",
        },
      },
    })
      .then((response) => {
        console.log(response);
        toast.success("Movie added successfully", {
          position: toast.POSITION.TOP_RIGHT,
        });
      })
      .catch((error) => {
        console.log("the error has occured: " + error);
      });

    setMovies([...movies, data]);
  }

  function addForm() {
    setshowEditForm(false);
    setshowAddForm(true);
  }

  function closeForm() {
    setshowAddForm(false);
    setshowEditForm(false);
    setMovie("");
  }

  function editForm(movie) {
    setMovie("");
    setshowAddForm(false);
    setshowEditForm(true);
    setMovie(movie);
  }

  function deleteMovie(id) {
    setshowEditForm(false);
    setMovie("");
    axios.delete(`http://localhost:5159/api/movies/${id}`).then(() => {
      toast.success("Movie deleted successfully", {
        position: toast.POSITION.TOP_RIGHT,
      });
    });

    setMovies([...movies.filter((x) => x.id !== id)]);
  }

  return (
    <div>
      <NavBar addForm={addForm} />
      <h1>Movies Data</h1>
      <MoviesDashboard
        movies={movies}
        showAddForm={showAddForm}
        showEditForm={showEditForm}
        editForm={editForm}
        movie={movie}
        deleteMovie={deleteMovie}
        closeForm={closeForm}
        handleSumbit={handleSumbit}
        handleEditMovie={handleEditMovie}
      />
      <ToastContainer position="top-center" />
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Update the index.css with the below code for styling

body {
  background-color: #eaeaea !important;
}
.ui.inverted.top.fixed.menu {
  background-image: linear-gradient(135deg,rgb(233, 10, 204) 0%, rgb(155, 50, 133) 69%,rgb(104, 50, 85) 89%) !important;
}
Enter fullscreen mode Exit fullscreen mode

*Test the Movies UI *

Home Page:

Image description

Add Movie :

Image description

Image description

Edit Movie :

Image description

Image description

In the next section we will explain the way to containerize the .NET Core 6.0 Web API and React applications.

You can find the full project in this GitHub repository.

Top comments (3)

Collapse
 
pauljlucas profile image
Paul J. Lucas

Why is this tagged #c? There's no C code here.

Collapse
 
webjose profile image
José Pablo Ramírez Vargas

Tip: If you add the language name after the opening 3 backticks of your code blocks, the code will be colorized.

Collapse
 
jayavardhan5555 profile image
Jayavardhan Reddy J

Thank you for the tip.