Merapihkan dan menyederhanan code

Buat file baru di folder Common dengan nama Table.jsx

Table.jsx

import React from "react";
import TableHeader from '../tableHeader'
import TableBody from '../tableBody';

const Table = ({ columns, sortColumn, onSort, data}) => {

    return (
        <table className="table">
            <TableHeader 
                columns={columns} 
                sortColumn={sortColumn}
                onSort={onSort}
            />
            <TableBody columns={columns} data={data}/>
            
        </table>
    );
}

export default Table;

Setelah itu ubah code di file moviesTable.jsx

import React, { Component } from 'react';
import Table from './Common/Table';
import Like from './Common/Like';

// const x = <Like></Like>;


class MoviesTable extends Component {
    columns = [
        { path: 'title', label: 'Title' },
        { path: 'genre.name', label: 'Genre' },
        { path: 'numberInStock', label: 'Stock' },
        { path: 'dailyRentalRate', label: 'Rate' },
        { key: "like",
          content: movie => <Like liked={movie.liked} onClick={() => this.props.onLike(movie)} />
        },
        { key: "delete",
          content: movie => (
            <button 
                onClick={() => this.props.onDelete(movie)}
                className="btn btn-danger btn-sm">
                Delete
            </button>
          )
            
        }
    ]
    
    render(){
        const { movies, onSort, sortColumn } = this.props;

        return (
            <Table 
                columns={this.columns} 
                data={movies}
                sortColumn={sortColumn}
                onSort={onSort}
            />
        )
    }
}

export default MoviesTable

Dan ubah jg file tableBody.jsx

import React, { Component } from "react";
import _ from 'lodash';

class TableBody extends Component {
    renderCell = (item, column) => {
        if(column.content) return column.content(item);

        return _.get(item, column.path);
    }

    createKey = (item, column) => {
        return item._id + (column.path || column.key);
    }

    render() {
        const { data, columns } = this.props;

        return(
            <tbody>
                {data.map(item => (
                    <tr key={item._id}>
                        {columns.map(column => (
                            <td key={this.createKey(item, column)}>
                                { this.renderCell(item, column) }
                            </td>
                        ))}
                    </tr>
                ))}
            </tbody>
        )
    }
}

export default TableBody

tableHeader.jsx

import React, { Component } from "react";

// colums: array
// sortColumn: object
// onSort: function
class TableHeader extends Component {
    raiseSort = path => {
        const sortColumn = { ...this.props.sortColumn };
        if(sortColumn.path === path)
            sortColumn.order = sortColumn.order === "asc" ? "desc" : "asc";
        else {
            sortColumn.path = path;
            sortColumn.order = "asc";
        }
        this.props.onSort(sortColumn);
    }

    renderSortIcon = column => {
        const { sortColumn } = this.props;

        if (column.path !== this.props.sortColumn.path) return null;
        if (this.props.sortColumn.order === 'asc') return <i className="fa fa-sort-asc" />;
        return <i className="fa fa-sort-desc" />
    };
    
    render() {
        return (
            <>
                <thead>
                    <tr>
                        { this.props.columns.map(column => (
                            <th 
                                className="clickable"
                                key={column.path || column.key } 
                                onClick={() => this.raiseSort(column.path)}
                            >
                                { column.label } { this.renderSortIcon(column) }
                            </th>
                        )) }
                    </tr>
                </thead>
            </>
        )
    }
}


export default TableHeader;

movies.jsx

import React, {Component} from 'react';
import ListGroup from './Common/listGroup';
import Pagination from './Common/Pagination';
import MoviesTable from './moviesTable';
import { getMovies } from '../services/fakeMovieService';
import { getGenres } from '../services/fakeGenreService';
import { paginate } from '../utils/paginate';
import _ from 'lodash';

class Movies extends Component {
    state = {
        movies: [],
        genres: [],
        currentPage: 1,
        pageSize: 4,
        sortColumn: { path: "title", order: "asc" }
    };

    componentDidMount() {
        const genres = [{ _id: "", name: 'All Genres'}, ...getGenres() ]

        this.setState({ movies: getMovies(), genres });
    }

    handleDelete = movie => {
        const movies = this.state.movies.filter(m => m._id !== movie._id);
        this.setState({ movies })
        // console.log(movie)
    }

    handleLike = movie => {
        const movies = [...this.state.movies];
        const index = movies.indexOf(movie);
        movies[index] = { ...movies[index] };
        movies[index].liked = !movies[index].liked;
        this.setState({ movies });

        // console dan ambil tiap data per id
        // console.log("like bos", movie)
    }

    handlePageChange = page => {
        this.setState({ currentPage: page });
        // console.log(page)
    }

    handleGenreSelect = genre => {
        this.setState({ selectedGenre: genre, currentPage: 1 })
    }
    
    handleSort = sortColumn => {
        
        this.setState({ sortColumn })

        // console.log(path)
    }

    getPagedData = () => {
        const { 
            pageSize, 
            currentPage, 
            sortColumn,
            selectedGenre, 
            movies: allMovies 
        } = this.state;

        const filtered = 
            selectedGenre && selectedGenre._id 
            ? allMovies.filter(m => m.genre._id === selectedGenre._id) 
            : allMovies;

        const sorted = _.orderBy(filtered, [sortColumn.path], [sortColumn.order]);
        const movies = paginate(sorted, currentPage, pageSize);

        return { totalCount: filtered.length, data:movies }
    }

    render() {
        const { lenght: count } = this.state.movies;
        const { pageSize, currentPage, sortColumn } = this.state;

        if( count === 0)
            return <p>There are no movies in the database</p>;

        const { totalCount, data: movies } = this.getPagedData();

        return (
            <>
            <div className="row">
                <div className="col-3">
                    <ListGroup 
                        items={this.state.genres}
                        selectedItem={this.state.selectedGenre}
                        onItemSelect={this.handleGenreSelect} 
                    />
                </div>
                <div className="col">
                    <p>Showing {totalCount} movies in the database</p>
                    
                    <MoviesTable 
                        movies={movies}
                        sortColumn={sortColumn}
                        onLike={this.handleLike}
                        onDelete={this.handleDelete}
                        onSort={this.handleSort}
                    />

                    <Pagination 
                        itemsCount={totalCount}
                        pageSize={pageSize} 
                        currentPage={currentPage}
                        onPageChange={this.handlePageChange} 
                    />
                </div>

                
            </div>
            </>
          )
    }
}

export default Movies

Codingan lebih sederhana dan terpisah pisah file nya, hasil nya pun akan tetap sama

Contoh code:

Last updated

Was this helpful?