react_on_railsでreduxを使う
前回の続きでreduxを導入しました。
必要なnpmを追加
redux-thunkは非同期アクションを実現するパッケージなのであまり関係ありませんが、後々入れることになると思うのでついでに入れておきます。
yarn add redux react-redux react-router-redux redux-thunk
コードにstoreを追加する
サーバサイドのルーター。
ブラウザのルーター。
コントローラにもstoreを追加する
# application_controller.rb def render_for_react(props: {}, status: 200) if request.format.json? response.headers["Cache-Control"] = "no-cache, no-store" response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" response.headers["Pragma"] = "no-cache" render( json: common_props.merge(props), status: status, ) else redux_store( "store", props: common_props.merge(props).as_json, ) render( html: view_context.react_component( "Router", prerender: true, ), layout: true, status: status, ) end end
テンプレートに<%= redux_store_hydration_data %>
を追加。
reducerを追加
propsとrailsContextをinitialStateにぶち込み、react-router-reduxの提供しているルーティングに関するreducerと後で作るその他のreducersを全部放り込んでcombineReducersでまとめます。
const initialState = { ...props, railsContext, }; const reducer = combineReducers({ ...reducers, routing: routerReducer, });
この時点でrailsContextReducerがないとエラーが発生するので、こいつを作っていきます。とはいっても最初のロード以外でこいつが処理を行うことは基本的にありませんのでstate
をそのまま返すだけのものです。
export default function railsContextReducer(state = {}) { return state; }
props
を出力すると以下のようにrouting
とrailsContext
が含まれていることがわかります(reduxのconnect
でstate
をそのままprops
にマッピングした場合の出力)。