react_on_rails
での新規アプリケーション作成でわかったことを踏まえ、react-rails
を組み込んだ既存アプリケーションからの移行を考える。
両者ともreact_component
でコンポーネントを呼び出すがシグニチャが異なるので、共存は考えずに一括で置き換える際に必要になった変更点を書く。
react-rails関連の記述の廃止
- マニフェスト
-//= require react
-//= require react_ujs
Gemfile
-gem 'react-rails'
+gem 'react_on_rails', '~> 6'
react_on_railsの起動シーケンスに沿った変更
- foremanを使ってRailsとWebpackを個別に起動する
-
Procfile
(Procfile.dev
)が動くようにする - WebpackのエントリポイントになるReactコンポーネントを作成しWebpack設定に記述する
- Reactコンポーネントを
client/
以下に隔離する-
.js.jsx
で終わっているファイルを.jsx
にリネームしないとバンドル時にエラーが出る。.js.jsx
を認める設定もあるような気がする
-
> 14:02:02 client.1 | Module not found: Error: Cannot resolve 'file' or 'directory' ./app/bundles/APP_NAME in /Users/satzz/APP_NAME/client
- Railsビューの変更
-
react_component
への引数の渡し方を変更する
-
依存解決
react-rails
がやってくれていたらしい部分を地道につぶす。
以下、コンポーネントはReact.createClass
で作られている前提。
コンポーネント間の依存解決
ほかのモジュールからの呼び出しがあるコンポーネントは、呼び出し側モジュールでimport
する。
import { ComponentXXX, ComponentXXX } from '../components/module1';
Railsからコンポーネントへの依存の解決
ビューからのreact_component
による呼び出しがあれば、エントリポイントのコードを修正する。
- エントリポイントで
import
import { ComponentXXX, ComponentXXX } from '../components/module1';
- エントリポイントで
ReactOnRails.register
ReactOnRails.register({
ComponentXXX,
ComponentXXX,
});
- Railsビューで、
react_component
にpropsを渡す
-= react_component 'ComponentXXX', some_prop: some_value
+= react_component 'ComponentXXX', props: {some_prop: some_value}
export
上記のいずれかでimport
されているコンポーネントはモジュール側でexport
する。
module.exports = { ComponentXXX, ComponentXXX, ComponentXXX, ComponentXXX };
よくみるエラー
以下のようなエラーをブラウザコンソールで見る場合は上の作業が漏れて依存解決に失敗していることが多い。少ないうちは手で対応できるが、バンドル自体は成功して中途半端に動いて気づきにくいし移行のモチベーションも削がれるので、依存解決用のnodeモジュール、エディタプラグインやCIなどを活用して最低限の手間でつぶしたいところではある。
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined.
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `ComponentXXX `.
ReactOnRails encountered an error while rendering component: ComponentXXX.Original message: ComponentYYY is not defined
コンポーネントの内容修正
基本的に個々のコンポーネントはほとんどそのまま使えるが、イベントハンドラについては修正した。
-
onmousedown
をonMouseDown
に変更 - 文字列で記述されたハンドラはfunctionへ変更
+ onMouseDown:
+ function() {
+ //処理;
+ },
JSX
onMouseDown={this.onMouseDown}