react-rails+redux インストール (Node.js無し版) †プロジェクト配下に node.js モジュールを入れずに react-rails + redux が動作可能な環境を作る。 とりあえず react-rails-redux-sample(※) を node.js モジュール無しで動かせるようにしたものを作成する。 railsプロジェクト作成 †rails new react-rails-redux Gemfile追記 †gem 'react-rails' bundle install †bundle install --path vendor/bundle react-railsセットアップ †rails g react:install Expected string default value for '--jbuilder'; got true (boolean) create app/assets/javascripts/components create app/assets/javascripts/components/.gitkeep insert app/assets/javascripts/application.js insert app/assets/javascripts/application.js insert app/assets/javascripts/application.js create app/assets/javascripts/components.js 設定ファイル編集 †config/environments/development.rb MyApp::Application.configure do config.react.variant = :development # 追記 config.react.addons = true # 追記 config.react.camelize_props = true # 追記 end onfig/environments/production.rb MyApp::Application.configure do config.react.variant = :production end ルーティング追加 †routes.rb Rails.application.routes.draw do root to: 'welcome#index' end コントローラ作成 †app/controllers/welcome_controller.rb class WelcomeController < ApplicationController def index end end ビュー作成 †app/views/welcome/index.html.erb <h1>Welcome#index</h1> <%= react_component('Root', {counter: 10}, {prerender: true} ) %> redux.js のダウンロード †https://cdnjs.com/ から 以下をダウンロード cd vendor/assets/javascripts/ wget https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js wget https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.2/react-redux.min.js wget https://cdnjs.cloudflare.com/ajax/libs/redux-thunk/2.1.0/redux-thunk.min.js application.js の編集 †app/assets/javascripts/application.js //= require jquery //= require jquery_ujs //= require turbolinks //= require react //= require react_ujs //= require redux.min // 追記 //= require react-redux.min // 追記 //= require redux-thunk.min // 追記 //= require components //= require_tree . js作成 †app/assets/javascripts/components/welcome/index.js.jsx /**************************************************************** * react-rails-redux-sample の components 配下の js をサーバサイドjsを使用しない形に変換したもの。 * ※https://github.com/suzan2go/react-rails-redux-sample ****************************************************************/ //--------------------------------------------------------- // components/actions/counter.js //--------------------------------------------------------- var INCREMENT_COUNTER = 'INCREMENT_COUNTER'; var DECREMENT_COUNTER = 'DECREMENT_COUNTER'; var SET_COUNTER = 'SET_COUNTER'; function setCounter(counter) { return { type: SET_COUNTER, counter: counter }; } function increment() { return { type: INCREMENT_COUNTER }; } function decrement() { return { type: DECREMENT_COUNTER }; } function incrementIfOdd() { return (dispatch, getState) => { const { counter } = getState(); if (counter % 2 === 0) { return; } dispatch(increment()); }; } function incrementAsync(delay = 1000) { return dispatch => { setTimeout(() => { dispatch(increment()); }, delay); }; } var CounterActions = { setCounter: setCounter ,increment: increment ,decrement: decrement ,incrementIfOdd: incrementIfOdd ,incrementAsync: incrementAsync }; //--------------------------------------------------------- // components/components/Counter.js //--------------------------------------------------------- class Counter extends React.Component { render() { const { increment, incrementIfOdd, incrementAsync, decrement, counter } = this.props; return ( <p> Clicked: {counter} times {' '} <button onClick={increment}>+</button> {' '} <button onClick={decrement}>-</button> {' '} <button onClick={incrementIfOdd}>Increment if odd</button> {' '} <button onClick={() => incrementAsync()}>Increment async</button> </p> ); } } Counter.propTypes = { increment: React.PropTypes.func.isRequired, incrementIfOdd: React.PropTypes.func.isRequired, incrementAsync: React.PropTypes.func.isRequired, decrement: React.PropTypes.func.isRequired, counter: React.PropTypes.number.isRequired }; //--------------------------------------------------------- // components/containers/CounterApp.js //--------------------------------------------------------- function mapStateToProps(state) { return { counter: state.counter } } function mapDispatchToProps(dispatch) { return Redux.bindActionCreators(CounterActions, dispatch); } var CounterApp = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Counter); //--------------------------------------------------------- // reducers/counter.js //--------------------------------------------------------- function counter(state = 0, action) { switch (action.type) { case INCREMENT_COUNTER: return state + 1; case DECREMENT_COUNTER: return state - 1; case SET_COUNTER: return action.counter; default: return state; } } //--------------------------------------------------------- // reducers/counter.js //--------------------------------------------------------- var rootReducer = Redux.combineReducers({ counter }); //--------------------------------------------------------- // components/store/configureStore.js //--------------------------------------------------------- var createStoreWithMiddleware = Redux.applyMiddleware(ReduxThunk)(Redux.createStore); /* このままでは動かない function configureStore(initialState) { return createStoreWithMiddleware(rootReducer, initialState); } */ // react-rails-redux-sample の js生成結果を参考に書き直し var createStoreWithMiddleware = (0, Redux.applyMiddleware)(ReduxThunk.default)(Redux.createStore); function configureStore(initialState) { return createStoreWithMiddleware(rootReducer, initialState); } //--------------------------------------------------------- // components/containers/Root.js //--------------------------------------------------------- var Provider = ReactRedux.Provider; var store = configureStore(); class Root extends React.Component { componentWillMount() { store.dispatch(setCounter(this.props.counter)); } render() { return ( <Provider store={store}> <CounterApp /> </Provider> ); } } |