react-rails+redux インストール (Node.js無し版)

プロジェクト配下に node.js モジュールを入れずに react-rails + redux が動作可能な環境を作る。

とりあえず react-rails-redux-sample(※) を node.js モジュール無しで動かせるようにしたものを作成する。
https://github.com/suzan2go/react-rails-redux-sample


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>
    );  
  }
}

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2017-01-12 (木) 02:16:30 (2655d)