1. susieyy

    No comment

    susieyy
Changes in tags
Changes in body
Source | HTML | Preview
@@ -1,227 +1,278 @@
[RESTfulAPIのFrontWebをAngular.jsで書こうかと思った](http://qiita.com/susieyy/items/8e860d4020d13eb8baeb)のですが、FRPパラダイムのReact.jsが面白そうなのでこちらで構築してみます。
## 環境
+ node.js v0.11.14
+ npm v2.1.11
+ bower v1.3.12
+ gulp v3.8.8
+ Yeoman v1.3.3
+ React.js latest
## インストール
nodeとnpmをインストールします。
```Shell
$ brew install node
$ brew install npm
```
npmで以下ライブラリをインストールします。
```Shell
$ npm install -g yo bower gulp generator-react-gulp-browserify
```
## ジェネレート
Yeomanで雛形プロジェクトをジェネレートします。
以下の項目を個別に設定できます。
```
❯◉ Sass with Compass
◉ Bootstrap
◉ Modernizr
◉ HTML template - Jade
◉ CoffeeScript for JavaScript
◉ Jest for unit tests
```
```Shell
$ mkdir Test
$ cd Test
$ yo react-gulp-browserify
_-----_
| |
|--(o)--| .--------------------------.
`---------´ | Welcome to Yeoman, |
( _´U`_ ) | ladies and gentlemen! |
/___A___\ '__________________________'
| ~ |
__'.___.'__
´ ` |° ´ Y `
You're using the fantastic React generator. We provide you full JavaScript solution with Sass support!
? What is this project's name? Test
❯◉ Sass with Compass
◉ Bootstrap
◉ Modernizr
◉ HTML template - Jade
◉ CoffeeScript for JavaScript
◉ Jest for unit tests
? What more would you like? Sass with Compass, Bootstrap, Modernizr, HTML template - Jade, CoffeeScript for JavaScript, Jest for unit tests
create package.json
create gulpfile.js
create bower.json
create app/styles/main.scss
create app/index.html
create app/scripts/app.coffee
create app/scripts/ui/Timer.coffee
create app/scripts/ui/__tests__/Timer-test.js
create app/favicon.ico
create .bowerrc
create .gitignore
create app/robots.txt
create .editorconfig
create .jshintrc
I'm all done. Running bower install & npm install for you to install the required dependencies. If this fails, try running the command yourself.
npm WARN package.json test@0.0.0 No description
npm WARN package.json test@0.0.0 No repository field.
npm WARN package.json test@0.0.0 No README data
bower not-cached git://github.com/Modernizr/Modernizr.git#^2.8.3
bower resolve git://github.com/Modernizr/Modernizr.git#^2.8.3
bower cached git://github.com/twbs/bootstrap-sass.git#3.3.1
bower validate 3.3.1 against git://github.com/twbs/bootstrap-sass.git#>=3.3.0
bower cached git://github.com/jquery/jquery.git#2.1.1
bower validate 2.1.1 against git://github.com/jquery/jquery.git#~2.1.1
bower cached git://github.com/jquery/jquery.git#2.1.1
bower validate 2.1.1 against git://github.com/jquery/jquery.git#>= 1.9.0
bower download https://github.com/Modernizr/Modernizr/archive/v2.8.3.tar.gz
bower extract modernizr#^2.8.3 archive.tar.gz
bower invalid-meta modernizr is missing "main" entry in bower.json
bower invalid-meta modernizr is missing "ignore" entry in bower.json
bower resolved git://github.com/Modernizr/Modernizr.git#2.8.3
npm WARN engine jest-cli@0.1.18: wanted: {"node":"0.8.x || 0.10.x"} (current: {"node":"0.11.14","npm":"2.1.11"})
> v8flags@1.0.8 install /Users/susieyy/tmp/yo/node_modules/gulp/node_modules/v8flags
> node fetch.js
bower new version for git://github.com/jquery/jquery.git#~2.1.1
bower resolve git://github.com/jquery/jquery.git#~2.1.1
bower new version for git://github.com/jquery/jquery.git#>= 1.9.0
bower resolve git://github.com/jquery/jquery.git#>= 1.9.0
bower download https://github.com/jquery/jquery/archive/2.1.3.tar.gz
bower download https://github.com/jquery/jquery/archive/2.1.3.tar.gz
bower extract jquery#~2.1.1 archive.tar.gz
bower extract jquery#>= 1.9.0 archive.tar.gz
bower resolved git://github.com/jquery/jquery.git#2.1.3
bower resolved git://github.com/jquery/jquery.git#2.1.3
bower install bootstrap-sass-official#3.3.1
bower install modernizr#2.8.3
bower install jquery#2.1.3
```
## 開発用RESTFulAPIサーバへのProxy設定
`/api`というPrefixでパスにアクセスした場合に、localhostの3000ポートにプロキシする設定を行います。
gulpでプロキシを行うために、以下のパッケージをインストールします。
```Shell
$ npm install --save-dev gulp-connect
$ npm install --save-dev proxy-middleware
```
続いて以下を`gulpfile.js`に追記します。
```gulpfile.js
var connect = require('gulp-connect');
var proxy = require('proxy-middleware');
var url = require('url');
gulp.task('connect', function() {
connect.server({
root: ['dist'],
port: 9000,
livereload: true,
// /apiにきたリクエストは http://localhost:3000/api にプロキシする。
middleware: function(connect, o) {
return [ (function() {
var options = url.parse('http://localhost:3000/api');
options.route = '/api';
return proxy(options);
})() ];
}
});
});
gulp.task('default', ['connect']);
```
## サーバ起動
localhostの9000ポートでアクセスできるようになります。
```Shell
$ gulp watch
```
![DevSpot_Front.jpg](https://qiita-image-store.s3.amazonaws.com/0/4943/80dc3e7d-2f99-7282-ca83-52db73b46ccc.jpeg "DevSpot_Front.jpg")
## コード
メインのスクリプトはこんな感じです。
React.jsが宣言的なので、簡素に表記するCoffeeScriptとも相性がよさそうです。
```app/scripts/app.coffee
###*
@jsx React.DOM
###
React = window.React = require("react")
Timer = require("./ui/Timer.coffee")
mountNode = document.getElementById("app")
TodoList = React.createClass(
displayName: "TodoList"
render: ->
createItem = (itemText) ->
React.createElement "li", null, itemText
React.createElement "ul", null, @props.items.map(createItem)
)
TodoApp = React.createClass(
displayName: "TodoApp"
getInitialState: ->
items: []
text: ""
onChange: (e) ->
@setState text: e.target.value
return
handleSubmit: (e) ->
e.preventDefault()
nextItems = @state.items.concat([@state.text])
nextText = ""
@setState
items: nextItems
text: nextText
return
render: ->
React.createElement "div", null, React.createElement(TodoList,
items: @state.items
), React.createElement("form",
onSubmit: @handleSubmit
, React.createElement("input",
onChange: @onChange
value: @state.text
), React.createElement("button", null, "Add #" + (@state.items.length + 1))), React.createElement(Timer, null)
)
React.renderComponent React.createElement(TodoApp, null), mountNode
```
+Javascriptの場合はこんな感じです。
+
+```app/scripts/app.js
+/** @jsx React.DOM */
+
+var React = window.React = require('react'),
+ Timer = require("./ui/Timer"),
+ mountNode = document.getElementById("app");
+
+var TodoList = React.createClass({
+ render: function() {
+ var createItem = function(itemText) {
+ return <li>{itemText}</li>;
+ };
+ return <ul>{this.props.items.map(createItem)}</ul>;
+ }
+});
+var TodoApp = React.createClass({
+ getInitialState: function() {
+ return {items: [], text: ''};
+ },
+ onChange: function(e) {
+ this.setState({text: e.target.value});
+ },
+ handleSubmit: function(e) {
+ e.preventDefault();
+ var nextItems = this.state.items.concat([this.state.text]);
+ var nextText = '';
+ this.setState({items: nextItems, text: nextText});
+ },
+ render: function() {
+ return (
+ <div>
+ <h3>TODO</h3>
+ <TodoList items={this.state.items} />
+ <form onSubmit={this.handleSubmit}>
+ <input onChange={this.onChange} value={this.state.text} />
+ <button>{'Add #' + (this.state.items.length + 1)}</button>
+ </form>
+ <Timer />
+ </div>
+ );
+ }
+});
+
+
+React.renderComponent(<TodoApp />, mountNode);
+```
+
+
+
## REF
+ [[JavaScript] 仮想DOMを提供する『React』について少し調べてみた](http://qiita.com/hkusu/items/ee5bc75c3c32185c7b76)
+ [React.jsについてのリソース、そして締め](http://qiita.com/koba04/items/9df76ac0744edd8f8e0e)
+ [一人React.js Advent Calendar 2014](http://qiita.com/advent-calendar/2014/reactjs)