LoginSignup
6
5

More than 3 years have passed since last update.

React + Rails のSPAでshowアクションを実装する

Posted at

これは何?

React+Railsで簡単なタスク管理アプリを作っています。
一覧画面からタスク名のリンクをクリックすると、詳細画面が現れます。

Image from Gyazo

実行環境は以下の通りです。

  • Rails 6.0.3
  • React 17.0.2

また、今回のディレクトリ構成は以下の通りです。(関係のある箇所だけ表示)

.
├── controllers
│   └── api
│       └── tasks_controller.rb
└── javascript
    └── pages
        ├── Task.jsx
        └── Tasks.jsx

Rails側

spaではないRailsのアプリとほぼ変わりありません。/api配下に置いたコントローラーにindex(実装については前回の記事をご参照ください)とshowアクションを記載します。

render json: ...でJSON形式でビューを描画します。

app/controllers/api/tasks_controller.rb
class Api::TasksController < ApplicationController
  def index
    @tasks = current_user.tasks
    render json: @tasks
  end

  def show
    @task = current_user.tasks.find(params[:id])
    render json: @task
  end
end

SPA側(一覧表示画面)

タスク一覧表示画面(Tasksコンポーネント)に実際に書いたコードがこちらです。

app/javascript/pages/Tasks.jsx
import React, {useState} from 'react'
import { Link, withRouter } from 'react-router-dom'
import axios from 'axios'

export const Tasks = withRouter(() => { // ★2解説します
  const [tasks, setTasks] = useState([])

  React.useEffect(async () =>{
    const response = await axios.get('/api/tasks');
    setTasks(response.data)
  }, [])

  return (
    <div>
      <h1>タスク一覧</h1>
      <table>
        // 中略
        <tbody>
          {tasks.map(task => (
            <tr key={task.id}>
              <td>
                <Link to={{ // ★1解説します
                  pathname: "/spa/tasks/" + task.id,
                  state: {id: task.id},
                  }}>{task.name}</Link>
              </td>
              // 中略
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
})

react-router と react-router-dom

まず、調べていて迷ったのが、react-routerreact-router-domがあるっぽいということ。その点は、こちらの記事が非常に丁寧に解説してくれていました。

要するに、react-router-domの方が新しくて使い勝手も良いそうなので、react-router-domを使いましょう、とのことでした。

Link to

ポイントの一つ目はこの部分(★1)で、

<Link to={{
  pathname: "/spa/tasks/" + task.id,
  state: {id: task.id},
}}>{task.name}</Link>

react-router-domLinkという関数で、遷移先や遷移先のページに送るデータなどが指定できます。詳しくは公式のAPIドキュメントがわかりやすかったですが、

上記を指定することで、受取手側のコンポーネントではlocatitonで以下のような情報が取得できました。

console.log(location)
=> {pathname: "/spa/tasks/1", state: {id: 1}, search: "", hash: "", key: "5ox837"}

withRouter

ただし、上記だけではlocationstateundefined になります。調べてみるとwithRouterでラップしてねという回答がたくさん出てきたので、今回も以下のように全体をラップしてみました(★2)。

export const Tasks = withRouter(() => {
 // 略
})

公式のドキュメントもみてみると、

withRouter will pass updated match, location, and history props to the wrapped component whenever it renders.

(withRouterは、レンダリングされるたびに、更新されたmatch、location、およびhistoryのpropsをラップされたコンポーネントに渡します。)

とのことでした。Functional ComponentでのwithRouterの使い方は、こちらを参考にしました。

完成

以上で、実装は終わりになります。
まさかShowアクションでここまで調べることになるとは思わなかった...^^
本日はDestroyアクションも試してみたのですが、そちらはまた別の機会に記事にしたいです。

ではでは。

6
5
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
6
5