source
Before moving on…let’s update our code to have more functionality
Decrement button
Add the onDecrement callback in our App’s render, and increment it to manipulate our state counters.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
import React, { Component } from 'react'; import NavBar from './components/NavBar'; import './App.css'; import Counters from "./components/counters"; class App extends Component { state = { counters: [ {id: 1, value: 0}, {id: 2, value: 0}, {id: 3, value: 0}, {id: 4, value: 0}, {id: 5, value: 0}, ] } cloneArray = (counter, callback) => { const counters = [...this.state.counters]; // clone array const index = counters.indexOf(counter); counters[index] = {...counter}; callback(counters, index); } handleIncrement = counter => { this.cloneArray(counter, (newArr, index) => { newArr[index].value++; this.setState({counters: newArr}); }); } handleDecrement = counter => { this.cloneArray(counter, (newArr, index) => { let item = newArr[index]; item.value = item.value > 0 ? item.value-1: 0; this.setState({counters: newArr}); }); } handleDelete = counterId => { const counters = this.state.counters.filter(c => c.id !== counterId); this.setState({ counters: counters }); } handleReset = () => { console.log('handleReset'); this.setState({ counters: [ {id: 1, value: 0}, {id: 2, value: 0}, {id: 3, value: 0}, {id: 4, value: 0}, {id: 5, value: 0}, ] }) } render() { return ( <React.Fragment> <NavBar totalCounters = {this.state.counters.filter(c => c.value > 0).length} /> <main className="container"> <Counters counters={this.state.counters} onReset={this.handleReset} onIncrement={this.handleIncrement} onDecrement={this.handleDecrement} onDelete={this.handleDelete} /> </main> </React.Fragment> ); } } export default App; |
Insert a decrement button, and other UI attributes.
counter.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
import React, { Component } from "react"; class Counter extends Component { constructor() { super(); console.log('-- Counter constructor --'); } getBadgeClasses() { let classes = "badge m-2 badge-"; classes += this.props.counter.value === 0 ? "warning" : "primary"; return classes; } formatCount() { const { value } = this.props.counter; return value === 0 ? "Zero" : value; } render() { return ( <div className='row'> <div className="col-1"> <span style={{width: '60px'}} className={this.getBadgeClasses()}>{this.formatCount()}</span> </div> <div className="col"> <button style={{marginRight: '10px'}} onClick={ () => this.props.onIncrement(this.props.counter)} className='btn btn-secondary btn-sm'> + </button> <button onClick={ () => this.props.onDecrement(this.props.counter)} className="btn btn-secondary btn-sm m-2" disabled={this.props.counter.value === 0 ? 'disabled' : 0} > - </button> <button onClick={() => this.props.onDelete(this.props.counter.id)} className="btn btn-danger btn-sm m-2">Delete</button> </div> </div> ); } } export default Counter; |
Add onDecrement props so counter component uses App component’s functionalities.
counters.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import React, { Component } from 'react'; import Counter from './counter'; class Counters extends Component { render() { return ( <div> <button onClick={this.props.onReset} className="btn btn-primary btn-sm m-2"> Reset </button> {this.props.counters.map(counter => ( <Counter counter={counter} key={counter.id} selected={true} onDelete={this.props.onDelete} onIncrement={this.props.onIncrement} onDecrement={this.props.onDecrement} /> ))} </div> ); } } export default Counters; |
Our Counters should look like this:
Movies
First import the services folder with fakeMoviesService.js and fakeGenreService.js files into your project.
Under components, create movies.jsx
We import getMovies function from our fakeMOvieService.js file and use them to fill up our state.
Then we simply use bootstrap’s table html in our render and display the data.
movies.jsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import React, { Component } from 'react'; import { getMovies } from '../../src/services/fakeMovieService'; class Movies extends Component { state = { movies: getMovies() } handleDelete = movie => { console.log(`Removing movie ${movie.title}`); // get all movies except our parameter movie // new array const movies = this.state.movies.filter(m => m._id !== movie._id); this.setState({movies}); }; render() { const { length: count} = this.state.movies; if (count === 0) return <p>No Movies in DB</p>; return ( <React.Fragment> <p>Showing {count} movies in the database.</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(movie => { return ( <tr key={movie._id}> <td>{movie.title}</td> <td>{movie.genre.name}</td> <td>{movie.numberInStock}</td> <td>{movie.dailyRentalRate}</td> <td><button onClick={() => this.handleDelete(movie)} className="btn btn-danger btn-sm">delete</button></td> </tr> ); })} </tbody> </table> </React.Fragment>) } } export default Movies; |
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
import Movies from './components/movies'; ... ... render() { return ( <React.Fragment> <NavBar totalCounters = {this.state.counters.filter(c => c.value > 0).length} /> <main className="container"> <Movies /> <Counters counters={this.state.counters} onReset={this.handleReset} onIncrement={this.handleIncrement} onDecrement={this.handleDecrement} onDelete={this.handleDelete} /> </main> </React.Fragment> ); } |