Posted at

react-railsからreact_on_railsへの移行

More than 3 years have passed since last update.

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


コンポーネントの内容修正

基本的に個々のコンポーネントはほとんどそのまま使えるが、イベントハンドラについては修正した。



  • onmousedownonMouseDownに変更

  • 文字列で記述されたハンドラはfunctionへ変更

+  onMouseDown:

+ function() {
+ //処理;
+ },

JSX

onMouseDown={this.onMouseDown}