React学習7(機能追加)
外部データから取得して一覧表示して、Like付けたり削除できたりできるところまで。
ファイル構成
. ├── App.js ├── Vidly.jsx ├── components │ ├── atoms │ │ └── Like.jsx │ └── molecules │ └── Movies.jsx ├── data │ └── services │ ├── fakeGenreService.js │ └── fakeMovieService.js └── index.js
ファイル中身
Vidly.jsx
import React, { Component } from 'react' import { getMovies } from './data/services/fakeMovieService' import Movies from './components/molecules/Movies' class Vidly extends Component { state = { movies: getMovies(), } constructor() { super() const { movies } = this.state this.state.movies = movies.map(movie => { movie.liked = false return movie }) } render() { const { movies } = this.state return ( <div className="container"> <main className="container" role="main"> <h1>Vidly</h1> <Movies movies={movies} onLike={this.handleLike} onDelete={this.handleDelete} /> </main> </div> ) } handleLike = movie => { const likedMovies = [...this.state.movies] const movieIndex = likedMovies.findIndex(m => m === movie) likedMovies[movieIndex].liked = !likedMovies[movieIndex].liked this.setState({ movies: likedMovies, }) } handleDelete = movie => { const filteredMovies = [...this.state.movies].filter(m => { return m !== movie }) this.setState({ movies: filteredMovies, }) } } export default Vidly
Movies.jsx
import React from 'react' import Like from '../atoms/Like' const Movies = ({ movies, onLike, onDelete }) => { if (movies.length === 0) return <p>There are no movies!</p> return ( <> <p>There are {movies.length} movies!</p> <table className="table"> <thead> <tr> <th scope="col">id</th> <th scope="col">Title</th> <th scope="col">Genre</th> <th>Like</th> <th></th> </tr> </thead> <tbody> {movies.map((movie, index) => ( <tr key={index}> <th scope="row">{movie._id}</th> <td>{movie.title}</td> <td>{movie.genre.name}</td> <td> <span onClick={() => onLike(movie)} style={{ display: 'inline-block', cursor: 'pointer' }} > <Like movie={movie} /> </span> </td> <td> <button onClick={() => onDelete(movie)} type="button" className="btn btn-danger" > Delete </button> </td> </tr> ))} </tbody> </table> </> ) } export default Movies
Like.jsx
import React from 'react' const Like = ({ movie }) => { return <i className={movie.liked ? 'fas fa-heart' : 'far fa-heart'} /> } export default Like
fakeMovieService.js
import * as genresAPI from './fakeGenreService' 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 }
fakeGenreService.js
export const genres = [ { _id: '5b21ca3eeb7f6fbccd471818', name: 'Action' }, { _id: '5b21ca3eeb7f6fbccd471814', name: 'Comedy' }, { _id: '5b21ca3eeb7f6fbccd471820', name: 'Thriller' }, ] export function getGenres() { return genres.filter(g => g) }