LoginSignup
0
0

ReactOnRailsのしくみ

Last updated at Posted at 2024-01-23

このコードは、ReactとReduxを使用するReact on Rails環境でのReduxストアの登録と初期データの挿入(hydration)のプロセスを示しています。それぞれのステップを詳しく説明します。

作成したstoreGeneratorを登録(registeredStoreGenerators配列に追加)

  register(storeGenerators: { [id: string]: Store }): void {
    Object.keys(storeGenerators).forEach(name => {
      if (registeredStoreGenerators.has(name)) {
        console.warn('Called registerStore for store that is already registered', name);
      }

      const store = storeGenerators[name];
      if (!store) {
        throw new Error('Called ReactOnRails.registerStores with a null or undefined as a value ' +
          `for the store generator with key ${name}.`);
      }

      registeredStoreGenerators.set(name, store);
    });
  },

初期データの準備 (Hydration)

redux_store ヘルパーメソッドは、サーバーサイドでのレンダリング時にReduxストアの初期データをセットアップします。このメソッドは、ストアの名前と初期プロパティを受け取り、それらを用いてクライアントサイドで利用するためのデータを生成します。defer 引数が true である場合、ストアのデータは後でレンダリングされることを意味し、false の場合は即時レンダリングされます。

react_on_rails/lib/react_on_rails/helper.rb
    def redux_store(store_name, props: {}, defer: false)
      # ... redux_storeのデータ構築 ...
      redux_store_data = { store_name: store_name,
                           props: props }
      if defer
        @registered_stores_defer_render ||= []
        @registered_stores_defer_render << redux_store_data
        "YOU SHOULD NOT SEE THIS ON YOUR VIEW -- Uses as a code block, like <% redux_store %> " \
          "and not <%= redux store %>"
      else
        @registered_stores ||= []
        @registered_stores << redux_store_data
        result = render_redux_store_data(redux_store_data)
        prepend_render_rails_context(result)
      end
    end

    def redux_store_hydration_data
      # ... デファードされたストアのデータを結合し、HTMLに安全な形でレンダリング ...
      return if @registered_stores_defer_render.blank?

      @registered_stores_defer_render.reduce(+"") do |accum, redux_store_data|
        accum << render_redux_store_data(redux_store_data)
      end.html_safe
    end

    def render_redux_store_data(redux_store_data)
      # ... redux_storeデータをHTMLのscriptタグとしてレンダリング ...
      result = content_tag(:script,
                           json_safe_and_pretty(redux_store_data[:props]).html_safe,
                           type: "application/json",
                           "data-js-react-on-rails-store" => redux_store_data[:store_name].html_safe)

      prepend_render_rails_context(result)
    end

クライアントサイドでのストアの初期化(storeの作成と準備した初期データの登録)

クライアントサイドでは、clientStartup 関数がページの準備ができた時に呼び出されます。この関数は、サーバーサイドから送られた初期データを元に、対応するReduxストアを初期化するための initializeStore 関数を呼び出します。

node_package/src/ReactOnRails.ts
ClientStartup.clientStartup(ctx);
node_package/src/clientStartup.ts
export function clientStartup(context: Context): void {
  // ... ページ準備完了時にレンダリングを初期化 ...
  // 省略
  onPageReady(renderInit);
  // =>なんやかんやあってinitializeStoreが呼び出される
}

// REACT_ON_RAILS_STORE_ATTRIBUTEは<%= redux_store_hydration_data %>で生成されるcontent_tagのkey
function initializeStore(el: Element, context: Context, railsContext: RailsContext): void {
  // ... 指定されたストアのデータを取得し、ストアを初期化 ...
  const name = el.getAttribute(REACT_ON_RAILS_STORE_ATTRIBUTE) || '';
  const props = (el.textContent !== null) ? JSON.parse(el.textContent) : {};
  const storeGenerator = context.ReactOnRails.getStoreGenerator(name);
  const store = storeGenerator(props, railsContext);
  context.ReactOnRails.setStore(name, store);
}

解説

const props = (el.textContent !== null) ? JSON.parse(el.textContent) : {};

はhydratedStores からinitial_dataを取得する。

const storeGenerator = context.ReactOnRails.getStoreGenerator(name);

はregisteredStoreGenerators からgenerator関数を取得する。

const store = storeGenerator(props, railsContext);

でregisteredStoreGenerators関数を使用して新しいstoreを生成。

context.ReactOnRails.setStore(name, store);

でhydratedStoresを更新。

アプリケーションでstore = getStore(store_name) を使用して取得するのはhydratedStores に入っている初期化済みのstoreです。
storeの更新は通常のreduxに戻るため特にreact_on_railsの処理は挟まないです。

0
0
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
0
0