LoginSignup
17
21

More than 5 years have passed since last update.

react-railsを使って、簡単なデータ表示+検索のサンプルを作ってみる

Last updated at Posted at 2018-12-24

はじめに

仕事でRailsを使用して開発をしているのですが、事情によりReactを導入することになりました。
しかし、「Reactって何?」状態の自分にとって、いきなりReactを導入と言われても...
なので、事前にReactを勉強するため、色々参考にしながら、簡単なサンプルを作ってみました。

使用した技術とバージョン

ruby 2.5.1
Rails 5.2.2
react-rails 2.4.7
WebPacker 3.5.5

参考にした記事や書籍

Reactの学習には、こちらの書籍を使用しました。
今回記述したサンプルコードも、こちらの内容を大いに参考にさせて頂きつつ、記述していきました。

吉田裕美 著「作りながら学ぶ React入門」(2017)
https://www.amazon.co.jp/%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E5%AD%A6%E3%81%B6-React%E5%85%A5%E9%96%80-%E5%90%89%E7%94%B0%E8%A3%95%E7%BE%8E/dp/479805075X/ref=sr_1_1?ie=UTF8&qid=1545646648&sr=8-1&keywords=%E4%BD%9C%E3%82%8A%E3%81%AA%E3%81%8C%E3%82%89%E5%AD%A6%E3%81%B6react%E5%85%A5%E9%96%80

また、絞り込み部分はこちらの記事を参考にさせて頂きました。
Reactで絞り込み機能付き検索を実装してみた

こちら2つについて、参考にさせて頂きありがとうございました。

成果物

タスクリスト.png

内容としてはシンプルで、タスク管理のページを作りました。
一応タスクの名前で検索できるようになってます。
(ちなみにタスクの登録は未実装...時間ができたら作ります。)

実装方法は?

上の画面は、全てReactで描画するようになっています。
よって、html自体には、Reactのコンポーネントを呼び出す処理しか書いてないです。

実装の流れ

1、前準備

react-railsのgithubに載っている方法でプロジェクトを作ったりしつつ、
Get started with Webpacker
まで進めます。
そこから、

rails g controller schedule
rails g model Task name:string description:text start_date:string end_date:string
rails db:migrate

で必要なコントローラやモデルを作り、DBとテーブルも作成します。
面倒ですが、タスク登録がないので、insert文でタスクを頑張って入れます...
(start_dateやend_dateがstringなのは、日付の処理が面倒だったからです...)

2、rails側の整備

コントローラ、ビュー、ルーティングに実装を追加し、rails側の準備を完了させます。
views/scheduleにindex.html.erbを追加し、以下のように実装を加えます。

index.html.erb
 <%= react_component("Task", { tasks: @tasks }) %>

またコントローラ、ルーティングは以下のようにします。

schedule_controller.rb
 class ScheduleController < ApplicationController
    def index
        @tasks = Task.all();
    end
end
routes.rb
Rails.application.routes.draw do
  get '/schedule', to: 'schedule#index', as: 'schedule'
end

Rails側でやっていることは、
①タスクを表示するためのページを作る
②コントローラで、DBからTaskを全て取得し、ビューに渡してあげる
③ビューでは、コントローラから渡ってきたTaskを、Reactコンポーネントに渡す
だけです。

3、Reactの実装

いよいよReactのソースを実装します。
app/javascript/components配下に、
Task.js
を追加します。
もしくは、

rails g react:component Task

でも作成できるようです。

今回実装した、Task.jsの中身は以下の通りです。
一応部分部分にコメントを入れて解説していますが、
間違ってたらごめんなさい... 

Task.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'

//メインのコンポーネント
class Task extends Component {
  //コンストラクタ。
  //このコンポーネントのstateには絞り込み前のタスク一覧と、絞り込み後のタスク一覧をそれぞれ用意する
  constructor(props){
    super(props)
    this.state = {initialTasks: this.props.tasks, tasks:[]}
  }

  //ブラウザロード時の処理。
  //最初はタスク全部を表示しておく
  componentDidMount() { 
    this.setState({tasks: this.state.initialTasks})
  }

  //検索のメソッドをここで用意しておく
  searchByName(name) { 
    const result = this.state.initialTasks.filter((task) => {
      return task.name.toLowerCase().search( name.toLowerCase()) !== -1;
    })
    this.setState({tasks: result})
  }

  /* 
    ページ全体のrenderメソッド。
    大事なのは、FilterFormのprops(search)に、上記で定義したsearchByNameを定義しておくこと。
    これにより、Taskコンポーネントのstateにあるtasksを変更することができる。
    そして、変更したtasksを、TaskListコンポーネントにpropsで渡してあげることで、
    絞り込み後のタスク一覧を表示することができる。
  */
  render() {
    return (
      <div>
        <h1>タスクリスト</h1>
        <FilterForm search={(name) => this.searchByName(name)} />
        <TaskList tasks={this.state.tasks} />
      </div>
    )
  }
}

//検索フォームのコンポーネント
class FilterForm extends Component{

  //コンストラクタ。ここでは、検索値nameをstateとして持っておく
  constructor(props){
    super(props)
    this.state = {name: ''}
  }

  //検索のテキストボックスの中身が変更された時の処理。
  //stateに検索値を挿入しておく
  onChangeName(event) {
    this.setState({name : event.target.value})
  }

  //検索ボタンをクリックされた時の処理。
  //上記で書いた通り、 Taskのコンポーネントで渡されたsearchメソッドを実行することにより、
  //Taskコンポーネントのstateに、絞り込み後のタスク一覧を表示することができる
  onClickSearch() {
    this.props.search(this.state.name)
  }

  //検索フォームのrenderメソッド。
  render() {
    return (
      <div className="entry">
        <fieldset>
          <legend>検索</legend>
          <div>名前で検索: <input type="text" value={this.state.name} name="name" onChange={(e) => this.onChangeName(e)} placeholder="例:買い物" /> </div>
          <div> <input type="submit" value="検索" onClick={(e) => this.onClickSearch(e)} /> </div>
        </fieldset>
      </div>
    )
  }
}

//タスク一覧についてのコンポーネント。
//こちらは上2つのクラスコンポーネントとは違い、関数コンポーネントになっている。
//クラスコンポーネントとは違い、できることが限られているため、シンプルな表示だけしたいときに使う。
const TaskList = (props) => { 
  //タスク一覧を表示する。
  //繰り返し処理にはmap関数を使用。
  return (
    <div>
      <table className="task">
        <thead  data-type="ok">
          <tr><th>名前</th><th>詳細</th><th>開始日</th><th>終了日</th></tr>
        </thead>
        <tbody>
          {props.tasks.map((task) =>
            <TaskItem task={task} key={task.id} /> )}
         </tbody>
      </table>
    </div>
  )
}
//TaskListコンポーネントが受け取るpropsを定義。
//ここではタスク一覧を受け取ることができるように定義しておく。
TaskList.propTypes = {
  tasks: PropTypes.array.isRequired
}

//タスクの1つの行を表すコンポーネント。
//上と同様関数コンポーネント。
const TaskItem = (props) => {
  //受け取ったタスクのオブジェクトの値を、それぞれ行のセルに挿入。
  const {name, description, start_date, end_date} = props.task
  return (
    <tr>
      <td>{name}</td>
      <td>{description}</td>
      <td>{start_date}</td>
      <td>{end_date}</td>
    </tr>
  )
}
//TaskItemコンポーネントが受け取るpropsを定義。
//ここではタスクオブジェクト。
TaskItem.propTypes = {
  task: PropTypes.object.isRequired
}

//react-railsではこの行がないとエラーになるっぽい。
//メインとなるクラス名(ここではTask)、ここで書いているクラス名、ファイル名の3つの名前が一緒じゃないと、
//エラーが起こって実行できなかった。
export default Task

Rails側から渡ってきたタスク一覧を、メインのTaskコンポーネントに渡すところから始まってます。
最初にこのページに遷移したときは、
①渡されたtasksを、TaskコンポーネントのstateのinitialTasksに入れて、それをそのまま同じstateのtasksに挿入する。
②state.tasksをTaskListコンポーネントに渡して、ループを回してTaskモデルの内容を抜き取って表示する
という感じの処理をしているかと思います。

一方、何かしらの検索がなされた時は、
①FilterFormにあらかじめ渡してあるsearchByNameメソッドを使って、入力値による絞り込みを行う(これにより、Taskコンポーネントのstate.tasksを更新することができる)。
②更新されたstate.tasksがTaskListコンポーネントに渡される。あとは上記と同様、ループを回してTaskモデルの内容を表示する
ということをしています。

実装できたら、

rails s

でサーバーを起動し、/scheduleにアクセスします。
タスク一覧が表示でき、絞り込みができたら成功!

最後に

Reactが全くわからない状態から、サンプルの力を借りてここまで来れました。
まだ触ったばかりなので内容としては全然かと思いますが、
これからReact+Railsを始める方にとって一助となれば幸いです。

ここまで読んで頂き、ありがとうございました!

17
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
21