React and .NET Core 6.0 Sample Project with Docker - Part 2
Jayavardhan Reddy J
Posted on October 16, 2022
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
After creating the react project open the application using visual studio code.
Go to Terminal => start the react app
npm start
Once you start the project , the UI will be open in your default browser.
Install packages:
- npm install semantic-ui-react semantic-ui-css
Open index.html page and past .css link in head section and .js after body section.
- npm install axios
- npm install react-toastify
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>
);
}
- 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>
);
}
- 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>
</>
);
}
- 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>
</>
);
}
- 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>
);
}
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;
}
*Test the Movies UI *
Home Page:
Add Movie :
Edit Movie :
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.
Posted on October 16, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 28, 2024
November 27, 2024