function foo()
{
}

2016年4月30日土曜日

Reactの勉強(4) - Reduxを使ってみる

1. reduxとreact-reduxをインストール
$ npm install redux react-redux --save
2. Counter.jsとPlusMinusButton.jsを削除
3. index.jsを以下のように変更
import React from 'react';
import  { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider, connect } from 'react-redux';

const reducer = (state={count: 0}, action) => {
  switch(action.type) {
    case 'PLUS_COUNT':
      return Object.assign({}, state, {count: state.count + 1});
    case 'MINUS_COUNT':
      return Object.assign({}, state, {count: state.count - 1});
    default:
      return state;
  }
};

const store = createStore(reducer);

const Counter = React.createClass({
  render() {
    return (
      <div>
         <h1>Counter </h1>
         <h2>{this.props.count} </h2>
         <button onClick={this.props.onPlusClick}>+ </button>
         <button onClick={this.props.onMinusClick}>- </button>
       </div>
    );
  }
});

function mapStateToProps(state) {
  return {
    count: state.count
  };
}

function mapDispatchToProps(dispatch) {
  return {
    onPlusClick() {
      dispatch({type: 'PLUS_COUNT'});
    },
    onMinusClick() {
      dispatch({type: 'MINUS_COUNT'});
    }
  };
}

const StatefulCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);

const App = () => {
  return (
    <div>
      <StatefulCounter />
    </div>
  );
}

render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('root')
);

Reduxの主な要素は、Store, Reducer, Action。 Reducerはアクションに応じて新しい状態を作成する。Storeはアクションを受け取るとReducerを呼び出し、新しい状態を保持する。 connectによってReduxに結び付けられたCounterのpropsにステートとアクションが渡され、Storeを監視するようになる。状態が更新されるたびに関数MapStateToPropsを呼び出し、新しい状態をプロパティに変換し、それをもとにCounterは描画を更新する。

connectの第2引数がCounterのthis.props.onPlusClick/onMinusClickとして設定される。それぞれのボタンをクリックすると、アクションが作られdispatchによりReducerが呼ばれる。action.typeに従って、新しいステートが作られて画面が更新される。

Reactの勉強(3) - まだまだReact

カウントアップやカウントダウンができる画面を作ってみます

1. Reactのコンポーネントを作ります
- index.js
import React from 'react';
import ReactDOM from 'react-dom';

let Counter = React.createClass({
  render() {
    return (
      <h1>Counter</h1>
    );
  }
});
ReactDOM.render(<Counter />, document.getElementById('root'));
Counterと表示されるようになります。Reactではコンポーネントを組み合わせて画面を作るようです。
2. カウントアップとカウントダウンの機能を作っていきます。
- index.js
import React from 'react';
import ReactDOM from 'react-dom';

let Counter = React.createClass({
  getInitialState() {
    return {
      count: 10
    };
  },

  onPlusClick() {
    this.setState({count: this.state.count + 1});
  },

  onMinusClick() {
    this.setState({count: this.state.count -1 });
  },

  render() {
    return (
      <div>
        <h1>Counter</h1>
        <h2>{this.state.count}</h2>
        <button onClick={this.onPlusClick}>+</button>
        <button onClick={this.onMinusClick}>-</button>
      </div>
    );
  }
});
ReactDOM.render(<Counter />, document.getElementById('root'));
  • getInitialState: カウンタの初期値を用意するための関数。初期値を10にします
  • onPlusClick, onMinusClick: カウンタの値を増減させます。ボタンのonClickと結びつけます。
  • this.state.count: カウンタの値にアクセスします。

3. コンポーネントを別ファイルに分けます
- Counter.js
import React from 'react';

const Counter = React.createClass({
  getInitialState() {
    return {
      count: 10
    };
  },

  onPlusClick() {
    this.setState({count: this.state.count + 1});
  },

  onMinusClick() {
    this.setState({count: this.state.count -1 });
  },

  render() {
    return (
      <div>
        <h1>Counter</h1>
        <h2>{this.state.count}</h2>
        <button onClick={this.onPlusClick}>+</button>
        <button onClick={this.onMinusClick}>-</button>
      </div>
    );
  }
});
export default Counter;
- index.js
import React from 'react';
import { render } from 'react-dom';
import Counter from './Counter';

render(<Counter />, document.getElementById('root'));
4. 親からカウンタへプロパティとしてタイトル文字列と初期値を渡すように変更します
- index.js
import React from 'react';
import { render } from 'react-dom';
import Counter from './Counter';

render(<Counter title="Counter Sample" initialCount={5}/>, document.getElementById('root'));
- Counter.js
import React from 'react';

const Counter = React.createClass({
  getInitialState() {
    return {
      count: this.props.initialCount
    };
  },

  onPlusClick() {
    this.setState({count: this.state.count + 1});
  },

  onMinusClick() {
    this.setState({count: this.state.count -1 });
  },

  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <h2>{this.state.count}</h2>
        <button onClick={this.onPlusClick}>+</button>
        <button onClick={this.onMinusClick}>-</button>
      </div>
    );
  }
});
export default Counter;
5. ボタンを再利用可能な部品にしてみます
- PlusMinuxButton.js
import React from 'react';

const PlusMinusButton = React.createClass({
  render() {
    return (
      <div>
        <button onClick={this.props.onPlusClick}>{this.props.plus}</button>
        <button onClick={this.props.onMinusClick}>{this.props.minus}</button>
      </div>
    );
  }
});

export default PlusMinusButton;
- Counter.js
import React from 'react';
import PlusMinusButton from './PlusMinusButton';

const Counter = React.createClass({
  getInitialState() {
    return {
      count: this.props.initialCount
    };
  },

  onPlusClick() {
    this.setState({count: this.state.count + 1});
  },

  onMinusClick() {
    this.setState({count: this.state.count -1 });
  },

  render() {
    return (
      <div>
        <h1>{this.props.title}</h1>
        <h2>{this.state.count}</h2>
        <PlusMinusButton
          onPlusClick = {this.onPlusClick}
          onMinusClick = {this.onMinusClick}
          plus = {this.props.plus}
          minus = {this.props.minus}
        />
      </div>
    );
  }
});
export default Counter;
- index.js
import React from 'react';
import { render } from 'react-dom';
import Counter from './Counter';

render(
  <div>
    <Counter title="Car" initialCount={0} plus="Saw Car" minus="Car Left" />
    <Counter title="Train" initialCount={0} plus="Saw Train" minus="Train Left" />
  </div>,
document.getElementById('root'));
6. PlusMinusButtonを関数型な部品に書き換えてみます
- PlusMinuxButton.js
import React from 'react';

const PlusMinusButton = ({onPlusClick, onMinusClick, plus, minus}) => {
    return (
      <div>
        <button onClick={onPlusClick}>{plus}</button>
        <button onClick={onMinusClick}>{minus}</button>
      </div>
    );
}

export default PlusMinusButton;

2016年4月29日金曜日

Reactの勉強(2) ... Reactを使い始める編

Reactを使い始めます
1. まずインストール
$ npm install --save-dev babel-preset-react
$npm install react react-dom --save
2. webpack.config.jsにReactのpresetを追加します
 
presets: ['es2015', 'react']
3. index.jsとindex.htmlだけ用意します。
- index.js
import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<h1>Hi</h1>, document.getElementById('root'));
- index.html
<html>
  <body>
    <div id="root">
    </div>
    <script charset="utf-8" src="bundle.js"></script>
  </body>
</html>
4. npm run buildしてからファイルにアクセスするとHelloと表示されます
5. そろそろbuildするのも面倒なので、勝手にbuildしてもらいます
$ npm install webpack-dev-server --save-dev
package.jsonのscriptに以下を追加
"watch": "./node_modules/.bin/webpack-dev-server"
$ npm run watch
ファイルを更新すると勝手にbuildしてくれます ブラウザからはhttp://localhost:8080でアクセスします。

2016年4月20日水曜日

Reactの勉強(1) ... Reactまでたどり着かない編

日々いろいろなものに襲われている。そんなわけで、今日はReact.jsとReduxの勉強。
Node.jsとはお付き合いがなかった人生を後悔中。

1. まずnodeをインストールしておきます。
$ brew install node
2. 作業ディレクトリを作り移動。プロジェクトを作ります。質問に対してはひたすらデフォルト値で。package.jsonがカレントディレクトリにできます。
$ mkdir first_sample; cd first_sample
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (first_sample)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC)
About to write to /Users/miya/workspace/react/first_sample/package.json:

{
  "name": "first_sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Is this ok? (yes) yes
4. 深く考えずにindex.htmlとindex.jsを用意します。
- index .html
<html>
  <body>
    <script charset="utf-8" src="bundle.js"></script>
  </body>
</html>
- index .js
  
console.log('Hello World!');
5. webpackをインストールします。webpackは依存を一つのファイルにまとめてくれます。
$ npm install webpack --save-dev
npm installの--save-devオプションは、これをつけるとpackage.jsonのdevDependenciesにwebpackを追加してくれます。

6. bundle.jsを作ります
$ ./node_modules/.bin/webpack index.js bundle.js
7. ブラウザでファイルを開くと、コンソールに「Hello World!」と表示されます(Javaコンソールを開いて確認してください) 
8. webpackを毎回長いコマンド叩くのは面倒だなぁ〜と思ったら、package.jsonのscriptに以下を追加し、webpack.config.jsを記述する。
-package.json
  "scripts": {
    "build": "./node_modules/.bin/webpack"
  },
- webpack.config.js
 module.exports = {
  entry: "./index.js",
   output: {
       path: __dirname,
       filename: "bundle.js"
    }
};
$ npm run build
で実行できるようになる
9. jsを二つに分けてみます。
- document.js
module.exports = function() {
  console.log('Hello World!');
};
- index.js
var run = require('./document.js');
run();

npm run build した後でブラウザにアクセスすると、ちゃんとHello Worldが表示されています。
10. ES6っぽく書き換えます
- document.js
  
export default function() {
    console.log('Hello World!');
 };
- index.js
 
 import run from './document';
 run();
11. babelをインストール
$ npm install babel-loader babel-core babel-preset-es2015 --save-dev
12. webpack.config.jsを書き換える
module.exports = {
  entry: "./index.js",
  output: {
    path: __dirname,
    filename: "bundle.js"
  },
  module: {
    loaders: [{
      test: /\.jsx?$/,
      exclude: /(node_modules|bower_components)/,
      loader: 'babel',
      query: {
        presets:['es2015']
      }
    }]
  }
};
13. npm run build してからファイルにアクセス