Make it to make it

いろいろ作ってアウトプットするブログ

React学習2(外部データの読み込みと表示)

React復習がてら要点をまとめていく。

外部ファイルの配列形式のデータを読み込んできて、画面に表示する例。

要点整理

  • Conditional renderingをするときは、returnするブロックを別メソッドで分けておくとやりやすい。
  • 読み込むデータに対してgetter, setter的なファンクションを用意しておくとデータ操作しやすくて便利。

ファイル構成

Vidly.jsx

import React, { Component } from 'react'
import { getMovies } from './data/services/fakeMovieService'

class Vidly extends Component {
  state = {
    movies: getMovies(),
  }

  render() {
    return (
      <div className="container">
        <main className="container" role="main">
          <h1>Vidly</h1>
          {this.renderMovies()}
        </main>
      </div>
    )
  }

  renderMovies = () => {
    const { movies } = this.state

    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></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>
                  <button
                    onClick={() => this.handleDelete(movie)}
                    type="button"
                    className="btn btn-danger"
                  >
                    Delete
                  </button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </>
    )
  }

  handleDelete = movie => {
    const filteredMovies = this.state.movies.filter(m => {
      return m !== movie
    })

    this.setState({
      movies: filteredMovies,
    })
  }
}

export default Vidly

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)
}