CRUD Operations Using ASP.NET Core Web API And ReactJS

This article will explain how to create React Js application and consume ASP.NET Core Web API requests to fetch the movie's data.

We will go through step by step with an example.

Please refer to my previous article on how to create ASP.NET Core Web APIs to fetch the data.

We need the following tools installed on our computer,

  • Visual Studio Code 

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 the Command Prompt and navigate to the path where you want to create the React application.

Command to create a React App: npx create-react-app movies-app

CRUD Operations Using ASP.NET Core Web API And ReactJS

Open the application using Visual Studio Code.

CRUD Operations Using ASP.NET Core Web API And ReactJS

Go to Terminal => start the react app using "npm start

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

Install packages

Go to VsCode Terminal and execute the below NPM packages one by one.

Add Components

Go to Movies App folder in VS Code => src => Create "Components" folder

Step 1

Create a .jsx file in the components folder and name it NavBar.jsx

We will use this file to add the Navigation to our Movies 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>
  );
}

Now create one more file for the movies table and name it as MoviesTable.jsx

This component displays the table with movie details and actions 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>
  );
}

Components => AddMovie.jsx

This component will be used to add the movie details to the database and display them in the 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>
    </>
  );
}

Components => EditMovie.jsx

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

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>
    </>
  );
}

Components => MoviesDashboard.jsx

This will be used to display 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>
  );
}

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;

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;
}

Now go to the browser where we started the application.

Home Page

CRUD Operations Using ASP.NET Core Web API And ReactJS

Add Movie

CRUD Operations Using ASP.NET Core Web API And ReactJS

Edit Movie

CRUD Operations Using ASP.NET Core Web API And ReactJS

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.

Thanks for reading!

Please leave a comment if you find this helpful. Any feedback or suggestions are welcome.