Movieslibrary Project Using ReactJS
Create the movieslibrary project using below command
E:\>create-react-app movieslibrary
Install below two libraries to your current project. Navigate to movieslibrary project root
E:\>cd movieslibrary
E:\>movieslibrary>npm i bootstrap@4.1.1 font-awesome@4.7.0
Add the below references to the index.js file
import 'bootstrap/dist/css/bootstrap.css';
import 'font-awesome/css/font-awesome.css';
Open the project using Visual Basic Code.
E:\movieslibrary>code .
Run the application using development server/ light server
E:\movieslibrary>npm start
Add a folder named services to the src folder
Add genreService.jsx file to services folder. And add the below code to this file.
genreService.jsx
export const genres = [
{ _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
{ _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
{ _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" }
];
export function getGenres() {
return genres.filter(g => g);
}
Add movieService.jsx file to the services folder and add the below code.
movieService.jsx
import * as genresAPI from "./genreService";
const movies = [
{
_id: "5b21ca3eeb7f6fbccd471815",
title: "Terminator",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 6,
dailyRentalRate: 2.5,
publishDate: "2018-01-03T19:04:28.809Z"
},
{
_id: "5b21ca3eeb7f6fbccd471816",
title: "Die Hard",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 5,
dailyRentalRate: 2.5
},
{
_id: "5b21ca3eeb7f6fbccd471817",
title: "Get Out",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 8,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471819",
title: "Trip to Italy",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181a",
title: "Airplane",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181b",
title: "Wedding Crashers",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181e",
title: "Gone Girl",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 7,
dailyRentalRate: 4.5
},
{
_id: "5b21ca3eeb7f6fbccd47181f",
title: "The Sixth Sense",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 4,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471821",
title: "The Avengers",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 7,
dailyRentalRate: 3.5
}
];
export function getMovies() {
return movies;
}
export function getMovie(id) {
return movies.find(m => m._id === id);
}
export function saveMovie(movie) {
let movieInDb = movies.find(m => m._id === movie._id) || {};
movieInDb.name = movie.name;
movieInDb.genre = genresAPI.genres.find(g => g._id === movie.genreId);
movieInDb.numberInStock = movie.numberInStock;
movieInDb.dailyRentalRate = movie.dailyRentalRate;
if (!movieInDb._id) {
movieInDb._id = Date.now();
movies.push(movieInDb);
}
return movieInDb;
}
export function deleteMovie(id) {
let movieInDb = movies.find(m => m._id === id);
movies.splice(movies.indexOf(movieInDb), 1);
return movieInDb;
}
Replace the app.js code with below code.
import React, { Component } from 'react';
import './App.css';
class App extends Component {
render() {
return (
<main className="container">
</main>
);
}
}
export default App;
After saving the file you will get a plain web page without any data rendered on it.
Add folder components to the src folder. Then add movies.jsx file to this folder. And add the below code.
movies.jsx
import React, { Component } from 'react';
class Movies extends Component {
state = { }
render() {
return ( <h2>Movies Library</h2> );
}
}
export default Movies;
Replace the code in app.js file as below and save the file to see the output in the browser.
import React, { Component } from 'react';
import './App.css';
import Movies from './components/movies';
class App extends Component {
render() {
return (
<main className="container">
<Movies></Movies>
</main>
);
}
}
export default App;
Now edit the movies.jsx file as below:
import React, { Component } from 'react';
import {getMovies} from '../services/movieService';
class Movies extends Component {
state = {
movies:getMovies()
};
render() {
return <table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies=>(<tr>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
</tr>))}
</tbody>
</table>
}
}
export default Movies;
Look at the output. You will get the list of movies in the browser screen.
Now add a Delete button for each row. Below is the code.
import React, { Component } from 'react';
import {getMovies} from '../services/movieService';
class Movies extends Component {
state = {
movies:getMovies()
};
render() {
return <table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies=>(<tr>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td>
<button type="button" class="btn btn-small btn-danger">button</button>
</td>
</tr>))}
</tbody>
</table>
}
}
export default Movies;
Now implement the Delete Button Event Handler. Below is the updated code to handle delete button.
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
class Movies extends Component {
state = {
movies: getMovies()
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id != movie._id);
this.setState({ movies: movies });
};
render() {
return <table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td>
<button onClick={()=>this.handleDelete(movies)} type="button" class="btn btn-small btn-danger">button</button>
</td>
</tr>))}
</tbody>
</table>
}
}
export default Movies;
Conditional rendering of movies database. This means we need to show at the top how many movies currently present in the database and when we delete one movie this should be updated automatically. When there are no movies in the database or when we delete all the movies it should show a message. See the below code changes and check the output in the browser.
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
class Movies extends Component {
state = {
movies: getMovies()
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id != movie._id);
this.setState({ movies: movies });
};
render() {
if(this.state.movies.length === 0)
return <p><h2>There are no movies in the Database</h2></p>;
return( <React.Fragment>
<p><h3>Showing {this.state.movies.length} movies from the database</h3></p>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td>
<button onClick={()=>this.handleDelete(movies)} type="button" class="btn btn-small btn-danger">button</button>
</td>
</tr>))}
</tbody>
</table>
</React.Fragment>
)};
}
export default Movies;
Now add one like button in the movies library. Create a folder “common” inside the components folder. Keep all common code which can be reusable throughout the application. Below is the updated code.
like.jsx
import React, { Component } from 'react';
class Like extends Component {
state = { }
render() {
return (
<i className="fa fa-heart-o" aria-hidden="true"></i>
);
}
}
export default Like;
movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
class Movies extends Component {
state = {
movies: getMovies()
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id != movie._id);
this.setState({ movies: movies });
};
render() {
if(this.state.movies.length === 0)
return <p><h2>There are no movies in the Database</h2></p>;
return( <React.Fragment>
<p><h3>Showing {this.state.movies.length} movies from the database</h3></p>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like></Like> </td>
<td>
<button onClick={()=>this.handleDelete(movies)} type="button" class="btn btn-small btn-danger">button</button>
</td>
</tr>))}
</tbody>
</table>
</React.Fragment>
)};
}
export default Movies;
Now change the state of like button.
Change the code in like.jsx
like.jsx
import React, { Component } from 'react';
class Like extends Component {
state = { }
render() {
let classes="fa fa-heart";
if(!this.props.liked)
classes+="-o"
return (
<i className={classes} aria-hidden="true"></i>
);
}
}
export default Like;
movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
class Movies extends Component {
state = {
movies: getMovies()
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id != movie._id);
this.setState({ movies: movies });
};
render() {
if(this.state.movies.length === 0)
return <p><h2>There are no movies in the Database</h2></p>;
return( <React.Fragment>
<p><h3>Showing {this.state.movies.length} movies from the database</h3></p>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={true}></Like> </td>
<td>
<button onClick={()=>this.handleDelete(movies)} type="button" class="btn btn-small btn-danger">button</button>
</td>
</tr>))}
</tbody>
</table>
</React.Fragment>
)};
}
export default Movies;
In the above like button is hard coded. We can make it dynamic by passing
<td><Like liked={movies.like}></Like> </td>
Change the code in movieservice and add some data like in it as follows:
movieService.jsx
import * as genresAPI from "./genreService";
const movies = [
{
_id: "5b21ca3eeb7f6fbccd471815",
title: "Terminator",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 6,
dailyRentalRate: 2.5,
publishDate: "2018-01-03T19:04:28.809Z",
like: true
},
{
_id: "5b21ca3eeb7f6fbccd471816",
title: "Die Hard",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 5,
dailyRentalRate: 2.5
},
{
_id: "5b21ca3eeb7f6fbccd471817",
title: "Get Out",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 8,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471819",
title: "Trip to Italy",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5,
like: true
},
{
_id: "5b21ca3eeb7f6fbccd47181a",
title: "Airplane",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181b",
title: "Wedding Crashers",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181e",
title: "Gone Girl",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 7,
dailyRentalRate: 4.5
},
{
_id: "5b21ca3eeb7f6fbccd47181f",
title: "The Sixth Sense",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 4,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471821",
title: "The Avengers",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 7,
dailyRentalRate: 3.5
}
];
export function getMovies() {
return movies;
}
export function getMovie(id) {
return movies.find(m => m._id === id);
}
export function saveMovie(movie) {
let movieInDb = movies.find(m => m._id === movie._id) || {};
movieInDb.name = movie.name;
movieInDb.genre = genresAPI.genres.find(g => g._id === movie.genreId);
movieInDb.numberInStock = movie.numberInStock;
movieInDb.dailyRentalRate = movie.dailyRentalRate;
if (!movieInDb._id) {
movieInDb._id = Date.now();
movies.push(movieInDb);
}
return movieInDb;
}
export function deleteMovie(id) {
let movieInDb = movies.find(m => m._id === id);
movies.splice(movies.indexOf(movieInDb), 1);
return movieInDb;
}
Now we will implement the click event of the like button.
Movieservice.jsx
import * as genresAPI from "./genreService";
const movies = [
{
_id: "5b21ca3eeb7f6fbccd471815",
title: "Terminator",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 6,
dailyRentalRate: 2.5,
publishDate: "2018-01-03T19:04:28.809Z",
likedOrNot: true
},
{
_id: "5b21ca3eeb7f6fbccd471816",
title: "Die Hard",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 5,
dailyRentalRate: 2.5,
likedOrNot: true
},
{
_id: "5b21ca3eeb7f6fbccd471817",
title: "Get Out",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 8,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471819",
title: "Trip to Italy",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5,
likedOrNot: true
},
{
_id: "5b21ca3eeb7f6fbccd47181a",
title: "Airplane",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181b",
title: "Wedding Crashers",
genre: { _id: "5b21ca3eeb7f6fbccd471814", name: "Comedy" },
numberInStock: 7,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd47181e",
title: "Gone Girl",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 7,
dailyRentalRate: 4.5
},
{
_id: "5b21ca3eeb7f6fbccd47181f",
title: "The Sixth Sense",
genre: { _id: "5b21ca3eeb7f6fbccd471820", name: "Thriller" },
numberInStock: 4,
dailyRentalRate: 3.5
},
{
_id: "5b21ca3eeb7f6fbccd471821",
title: "The Avengers",
genre: { _id: "5b21ca3eeb7f6fbccd471818", name: "Action" },
numberInStock: 7,
dailyRentalRate: 3.5
}
];
export function getMovies() {
return movies;
}
export function getMovie(id) {
return movies.find(m => m._id === id);
}
export function saveMovie(movie) {
let movieInDb = movies.find(m => m._id === movie._id) || {};
movieInDb.name = movie.name;
movieInDb.genre = genresAPI.genres.find(g => g._id === movie.genreId);
movieInDb.numberInStock = movie.numberInStock;
movieInDb.dailyRentalRate = movie.dailyRentalRate;
if (!movieInDb._id) {
movieInDb._id = Date.now();
movies.push(movieInDb);
}
return movieInDb;
}
export function deleteMovie(id) {
let movieInDb = movies.find(m => m._id === id);
movies.splice(movies.indexOf(movieInDb), 1);
return movieInDb;
}
like.jsx
import React, { Component } from 'react';
class Like extends Component {
state = { }
render() {
let classes="fa fa-heart";
if(!this.props.liked)
classes+="-o"
return (
<i className={classes} onClick={this.props.onClick} style={{cursor:'pointer'}} aria-hidden="true"></i>
);
}
}
export default Like;
movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
class Movies extends Component {
state = {
movies: getMovies()
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id !== movie._id);
this.setState({ movies: movies });
};
handleLike = movie => {
const movies=[...this.state.movies];
const index = movies.indexOf(movie);
movies[index]={...movies[index]};
movies[index].likedOrNot=!movies[index].likedOrNot;
this.setState({movies});
};
render() {
if (this.state.movies.length === 0)
return <h2>There are no movies in the Database</h2>;
return (<React.Fragment>
<h3>Showing {this.state.movies.length} movies from the database</h3>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={movies.likedOrNot} onClick={()=>this.handleLike(movies)} /></td>
<td>
<button onClick={() => this.handleDelete(movies)} type="button" className="btn btn-small btn-danger">Delete</button>
</td>
</tr>))}
</tbody>
</table>
</React.Fragment>
)
};
}
export default Movies;
Implementing pagination in the application:
Install lodash library to your project.
E:\movieslibrary>npm i lodash@4.17.10
Step-1
Add pagination.jsx file to the common folder and add below code:
import React from 'react';
import _ from 'lodash';
const Pagination = props => {
const { itemsCount, pageSize } = props;
const pagesCount = itemsCount / pageSize;
const pages = _.range(1, pagesCount + 1);
alert(pages);
return <nav>
<ul className="pagination">
{pages.map(page => (<li key={page} className="page-item">
<a className="page-link">{page}</a>
</li>))}
</ul>
</nav>
}
export default Pagination;
In the above code we have added state less function as we are not dealing with any type of states. Due to this we do not need any class. Function will full fill our requirement.
Add the Pagination tag to movies.jsx file as follows:
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
import Pagination from './common/pagination';
class Movies extends Component {
state = {
movies: getMovies(),
pagesize: 4
};
handlePageChange = page => {
console.log(page);
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id !== movie._id);
this.setState({ movies: movies });
};
handleLike = movie => {
const movies = [...this.state.movies];
const index = movies.indexOf(movie);
movies[index] = { ...movies[index] };
movies[index].likedOrNot = !movies[index].likedOrNot;
this.setState({ movies });
};
render() {
if (this.state.movies.length === 0)
return <h2>There are no movies in the Database</h2>;
return (<React.Fragment>
<h3>Showing {this.state.movies.length} movies from the database</h3>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={movies.likedOrNot} onClick={() => this.handleLike(movies)} /></td>
<td>
<button onClick={() => this.handleDelete(movies)} type="button" className="btn btn-small btn-danger">Delete</button>
</td>
</tr>))}
</tbody>
</table>
<Pagination
itemsCount={this.state.movies.length}
pageSize={this.state.pagesize}
onPageChange={this.handlePageChange}>
</Pagination>
</React.Fragment>
)
};
}
export default Movies;
Now implement when there are no items in movies database or when it shows only one page we do not need to show pagination:
See the below code:
movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
import Pagination from './common/pagination';
class Movies extends Component {
state = {
movies: getMovies(),
pagesize: 10
};
handlePageChange = page => {
console.log(page);
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id !== movie._id);
this.setState({ movies: movies });
};
handleLike = movie => {
const movies = [...this.state.movies];
const index = movies.indexOf(movie);
movies[index] = { ...movies[index] };
movies[index].likedOrNot = !movies[index].likedOrNot;
this.setState({ movies });
};
render() {
if (this.state.movies.length === 0)
return <h2>There are no movies in the Database</h2>;
return (<React.Fragment>
<h3>Showing {this.state.movies.length} movies from the database</h3>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={movies.likedOrNot} onClick={() => this.handleLike(movies)} /></td>
<td>
<button onClick={() => this.handleDelete(movies)} type="button" className="btn btn-small btn-danger">Delete</button>
</td>
</tr>))}
</tbody>
</table>
<Pagination itemsCount={this.state.movies.length} pageSize={this.state.pagesize} onPageChange={this.handlePageChange}></Pagination>
</React.Fragment>
)
};
}
export default Movies;
pagination.jsx
import React from 'react';
import _ from 'lodash';
const Pagination = props => {
const { itemsCount, pageSize } = props;
const pagesCount = Math.ceil(itemsCount / pageSize);
if(pagesCount === 1) return null;
const pages = _.range(1, pagesCount + 1);
alert(pages);
return <nav>
<ul className="pagination">
{pages.map(page => (<li key={page} className="page-item">
<a className="page-link">{page}</a>
</li>))}
</ul>
</nav>
}
export default Pagination;
Implementing the current page :
Movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
import Pagination from './common/pagination';
class Movies extends Component {
state = {
movies: getMovies(),
pagesize: 4,
currentpage:1
};
handlePageChange = page => {
this.setState({currentpage:page});
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id !== movie._id);
this.setState({ movies: movies });
};
handleLike = movie => {
const movies = [...this.state.movies];
const index = movies.indexOf(movie);
movies[index] = { ...movies[index] };
movies[index].likedOrNot = !movies[index].likedOrNot;
this.setState({ movies });
};
render() {
const {length:count}=this.state.movies;
const {pagesize, currentpage}=this.state;
if (this.state.movies.length === 0)
return <h2>There are no movies in the Database</h2>;
return (<React.Fragment>
<h3>Showing {this.state.movies.length} movies from the database</h3>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{this.state.movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={movies.likedOrNot} onClick={() => this.handleLike(movies)} /></td>
<td>
<button onClick={() => this.handleDelete(movies)} type="button" className="btn btn-small btn-danger">Delete</button>
</td>
</tr>))}
</tbody>
</table>
<Pagination
itemsCount={count}
pageSize={pagesize}
currnetPage={currentpage}
onPageChange={this.handlePageChange}>
</Pagination>
</React.Fragment>
)
};
}
export default Movies;
pagination.jsx
import React from 'react';
import _ from 'lodash';
const Pagination = props => {
const { itemsCount, pageSize, onPageChange, currnetPage } = props;
const pagesCount = Math.ceil(itemsCount / pageSize);
if (pagesCount === 1) return null;
const pages = _.range(1, pagesCount + 1);
return <nav>
<ul className="pagination">
{pages.map(page => (<li key={page} className={page === currnetPage ? 'page-item active' : 'page-item'}>
<a className="page-link" onClick={() => onPageChange(page)}>{page}</a>
</li>))}
</ul>
</nav>
}
export default Pagination;
Implement the pagination:
Create a folder named utils under the src folder where we will keep all reusable code and algorithms. These will be used by any project when required.
Create a file paginate.jsx and add the below code:
paginate.jsx
import _ from 'lodash';
export function paginate(items, pageNumber, pageSize) {
const startIndex = (pageNumber - 1) * pageSize;
return _(items).slice(startIndex).take(pageSize).value();
}
movies.jsx
import React, { Component } from 'react';
import { getMovies } from '../services/movieService';
import Like from './common/like';
import Pagination from './common/pagination';
import { paginate } from '../utils/paginate';
class Movies extends Component {
state = {
movies: getMovies(),
pagesize: 4,
currentpage:1
};
handlePageChange = page => {
this.setState({currentpage:page});
};
handleDelete = movie => {
const movies = this.state.movies.filter(x => x._id !== movie._id);
this.setState({ movies: movies });
};
handleLike = movie => {
const movies = [...this.state.movies];
const index = movies.indexOf(movie);
movies[index] = { ...movies[index] };
movies[index].likedOrNot = !movies[index].likedOrNot;
this.setState({ movies });
};
render() {
const {length:count}=this.state.movies;
const {pagesize, currentpage, movies:allmovies}=this.state;
if (this.state.movies.length === 0)
return <h2>There are no movies in the Database</h2>;
const movies=paginate(allmovies,currentpage,pagesize);
return (<React.Fragment>
<h3>Showing {this.state.movies.length} movies from the database</h3>
<table className="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Rate</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{movies.map(movies => (<tr key={movies._id}>
<td>{movies.title}</td>
<td>{movies.genre.name}</td>
<td>{movies.numberInStock}</td>
<td>{movies.dailyRentalRate}</td>
<td><Like liked={movies.likedOrNot} onClick={() => this.handleLike(movies)} /></td>
<td>
<button onClick={() => this.handleDelete(movies)} type="button" className="btn btn-small btn-danger">Delete</button>
</td>
</tr>))}
</tbody>
</table>
<Pagination
itemsCount={count}
pageSize={pagesize}
currnetPage={currentpage}
onPageChange={this.handlePageChange}>
</Pagination>
</React.Fragment>
)
};
}
export default Movies;
Now it will show you three pages. When you click on the page number you will get the respective movie records.
Type Checking in ReactJS: When you pass wrong type to a calling function you may not get any error in browser developer tool. At the run time only it come to know when unexpected result will be show. To check the strong type checking you can install a different package to your project:
Install the below package in your current project:
E:\movieslibrary>npm i prop-types@15.6.2
pagination.jsx
import React from 'react';
import _ from 'lodash';
import PropTypes from 'prop-types';
const Pagination = props => {
const { itemsCount, pageSize, onPageChange, currnetPage } = props;
const pagesCount = Math.ceil(itemsCount / pageSize);
if (pagesCount === 1) return null;
const pages = _.range(1, pagesCount + 1);
return <nav>
<ul className="pagination">
{pages.map(page => (<li key={page} className={page === currnetPage ? 'page-item active' : 'page-item'}>
<a className="page-link" onClick={() => onPageChange(page)}>{page}</a>
</li>))}
</ul>
</nav>
}
Pagination.PropTypes={
itemsCount:PropTypes.number.isRequired,
pageSize:PropTypes.number.isRequired,
onPageChange:PropTypes.func.isRequired,
currnetPage:PropTypes.number.isRequired
};
export default Pagination;
Now as we defined the prop types, we will get all type of type checking errors at development time only.
Nice Blog,
ReplyDeleteThe details that you mentioned in this blog regarding React js development.
I was searching for the best react js development company and found your blog.
Thanks for sharing such a great blog.