RailsのviewにReactを使ったのでメモ(React + TypeScript + webpacker)
最近仕事でRailsで新規に作るviewにReactを使うということをやったので、それについて書いておく。
前提
- これまではSprockets + CoffeeScriptで画面を作成していた
- React + TypeScriptで新規画面を作りたい
- 実際に画面を作るのはまだまだ先の話なので、現段階ではまずfeasibilityのチェックを優先してほしい
- 実際に僕が実装をするのではなくReactやTypeScriptに明るくない別の同僚が実装をする可能性もある
やったこと
webpackerの導入
Reactが動く環境をどうやって導入するかをまず悩んだ。
個人的にはRailsがフロントエンドの管理まですることがあまり好きではないため、webpackを使ってReactの動作環境をつくろうと思っていた。
だが前提に書いたように、実際には僕以外の人間が実装を行う可能性があるため、webpackの設定を一から作っていかなければならないwebpackよりも、webpackをラップしたgemであるwebpackerを使うことにした。
webpackerインストール後の手順としては以下の通り。
フロントで使うパッケージは個別にインストールしてもいいと思うが、土台作りくらいはwebpackerのみでできるっぽい。
# webpackerの初回インストール $ bundle exec rails webpacker:install # React向けの設定 $ bundle exec rails webpacker:install:react # TypeScript向けの設定 $ bundle exec rails webpacker:install:typescript # React用の型定義追加 $ yarn add @types/react @types/react-dom
ちなみに、この記事を書いてる中で気づいたが、react-railsやreact_on_railsっていうgemもあるらしい。これでもよかったかも。
RailsでAPI用コントローラーの作成
これはよくあるrender :json
でOK
React + TypeScriptで書く
ここからが本題。
ここに書いたのがベストプラクティスかは分からないが、参考になれば嬉しいので書いておく。
ディレクトリ構成
- /app - /javascripts - /packs - /entries - /someController - SomeControllerIndexEntry.tsx - SomeControllerShowEntry.tsx - /react - /someController - /pages - SomeControllerIndex.tsx - SomeControllerShow.tsx - /comp
まず、app/javascripts/packs/entries/someController
直下には、各ページで使うためのReactファイルを配置する。
これはエントリーファイルなので、中身的には/app/javascripts/react/somecontroller/pages
に配置したファイルを呼び出すだけ。
/app/javascripts/react/somecontroller/pages
直下には、そのページを構成するためのコンポーネントを書いたファイルを置く。
ページを構成する部品となる各コンポーネントは/app/javascripts/react/somecontroller/components
に置く。
あとは、この構成でビルドなどをするためにconfig/webpacker.yml
のsource_entry_path
をpacks/entries
にする。
こうすれば、
<%= javascript_pack_tag `someController/SomeControllerIndexEntry`%>
みたいにして、app/javascripts/packs/entries
以下のディレクトリ構成通りに呼び出せるようになる。
この構成だと、./bin/webpack
をしてビルドをすればpublic/packs/js/someControllers
配下にバンドルされた各ページごとのファイルが出力されるはず。
というか、開発環境でもwebpack-dev-serverを起動してない && public〜配下にバンドル済のファイルがないという場合にはwebpacker側がバンドルをするっぽいね。
csrf_tokenについて
今回はPOST処理も必要だったので、JSでよく使われてるFormData
を使ってPOSTをしようと思ったところcsrf tokenがないからPOSTを受け付けられないという旨のエラーが出た。
Railsのviewのmetaタグにはデフォルトで
<meta name="csrf-param" content="authenticity_token" /> <meta name="csrf-token" content="csrfToken" />
というものがあるので、
const csrfParam = (document.querySelector('meta[name="csrf-param"]') as HTMLMetaElement).content const csrfToken = (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement).content
こういう風に取って、
const form = new FormData() form.append(csrfParam, csrfToken)
というようにしてformに混ぜ込めば大丈夫。