m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

react.jsのjsxファイルをjsに変換してみる

以前作ったもの

reactjsで超単純なTODOアプリを作成してみた - m_shige1979のささやかな抵抗と欲望の日々

これが現在はjsxで作っている。
実際、jsxのほうが作りやすいけどなんかあれかもしれないので分割してみる

ついでにnode.jsの方法で作成

バージョン

react.0.14くらいに変更したかと…
npmでインストールしたら最新ものをとってきたので

npm

jsxからjsへ変換するモジュール
npm install browserify -g
reactとかjquery
npm install react reactify
npm install react-dom
npm install jquery

分割対応

index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Reactjs-TodoApp</title>
</head>
<body>
<div id="content"></div>
<script src="js/app.js"></script>
</body>
</html>
jsx/app.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var $ = require('jquery');

/**
 * TodoApp
 */
var TodoApp = React.createClass({

    getInitialState: function() {
        return {data: []};
    },

    // コンポーネントがレンダリングされた場合に呼ばれる
    componentDidMount: function() {
        this.setState({
            data: this.props.data
        });
    },

    render: function() {
        return (
            <div className="todoApp">
                <h1>TodoApp</h1>
                <TodoForm onAddSubmit={this.addList} />
                <TodoList data={this.state.data} onDelSubmit={this.delList} />
            </div>
        );
    },

    addList: function(item){
        // 取得
        var _data = this.state.data;
        var _data2 = _data.concat([item]);

        // 更新
        this.setState({data: _data2});
    },

    delList: function(item){
        // 取得
        var _data = this.state.data;

        // idが指定の場合は削除
        _data.some(function(v, i){
            if (v._id == item){
                _data.splice(i, 1);
            }
        });

        // 更新
        this.setState({data: _data});
    }
});

var TodoForm = React.createClass({

    onAddListSubmit: function(){

        // 値を取得
        var _text = ReactDOM.findDOMNode(this.refs.text).value.trim();
        if(!_text){
            return;
        }

        // 値を編集
        var _item = {
            _id: (new Date()).getTime(),
            text: _text
        }

        // 追加処理
        this.props.onAddSubmit(_item);

        // 初期化
        ReactDOM.findDOMNode(this.refs.text).value = '';
        return;

    },

    render: function() {
        return (
            <form className="todoForm">
                <span>タスク:</span>
                <input type="text" placeholder="入力…" ref="text" />
                <input type="button" value="追加" onClick={this.onAddListSubmit} />
            </form>
        );
    }
});

var TodoList = React.createClass({
    render: function() {

        // 削除ボタン
        var _btn = this.props.onDelSubmit;

        // this.props.dataをmap処理で定義
        var itemNodes = this.props.data.map(function (item) {
            return (
                <TodoItem dataKey={item._id} onDelListSubmit={_btn}>
                    {item.text}
                </TodoItem>
            );
        });

        return (
            <div className="todoList">
                {itemNodes}
            </div>
        );
    }
});
var TodoItem = React.createClass({

    getInitialState: function() {
        return {
            mode: {}
        };
    },

    componentDidMount: function() {
        this.setState({
            mode: {}
        });
    },

    onItemChange: function(e){

        var _checked = ReactDOM.findDOMNode(this.refs.chk).checked;
        if(_checked === true){
            this.setState({
                mode: {
                    "text-decoration": "line-through"
                }
            });
        }else{
            this.setState({
                mode: {}
            });
        }

    },

    delSubmit: function(){

        var _dataKey = $(ReactDOM.findDOMNode(this.refs.dataKey)).attr("data-key");
        this.props.onDelListSubmit(_dataKey);

        ReactDOM.findDOMNode(this.refs.chk).checked = false;
        this.setState({
            mode: {}
        });
    },

    render: function() {

        return (
            <div className="todoItem">
                <input type="button" value="削除" onClick={this.delSubmit} />
                <label>
                    <input type="checkbox" ref="chk" unchecked="unchecked" onChange={this.onItemChange}/>
                    <span data-key={this.props.dataKey} style={this.state.mode} ref="dataKey">{this.props.children}</span>
                </label>
            </div>
        );
    }
});

var _list = [
];
ReactDOM.render(
    <TodoApp data={_list}/>,
    document.getElementById('content')
);

変換コマンド

browserify -t reactify jsx/app.jsx > js/app.js

これでOK
※変換後のソースコードは2万行超えたw

バージョンが変わったのでちょっと修正している

今からはじめるReact.js〜React ver0.14〜 - Qiita
※まあ、仕方ない

gruntとかは

Gruntfile.js
module.exports = function (grunt) {
    var pkg = grunt.file.readJSON('package.json');

    grunt.initConfig({
        browserify : {
            dev: {
                options: {
                    debug: true,
                    transform: ['reactify']
                },
                files: {
                    'js/app.js': 'jsx/**/*.jsx'
                }
            }
        },
        watch : {
            scripts : {
                files : ['jsx/**/*.jsx'],
                tasks : ['browserify:dev']
            }
        }
    });

    Object.keys(pkg.devDependencies).forEach(function (devDependency) {
        if (devDependency.match(/^grunt\-/)) {
            grunt.loadNpmTasks(devDependency);
        }
    });

    grunt.registerTask('default', ['watch']);
};
gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var source = require("vinyl-source-stream");
var reactify = require('reactify');

gulp.task('browserify', function(){
    browserify('./jsx/app.jsx', { debug: true })
        .transform(reactify)
        .bundle()
        .on("error", function (err) { console.log("Error : " + err.message); })
        .pipe(source('app.js'))
        .pipe(gulp.dest('./js'));

});

gulp.task('watch', function() {
    gulp.watch('./jsx/*.jsx', ['browserify'])
});

gulp.task('default', ['watch']);

うーんなんかこの辺はまだ良くわかっていない

所感

javascriptで書くよりはjsxのほうが助かる場合もある…
問題としてはバグが発生した場合に何が原因かをうまく見つけられるかということかな?
browserifyでnodejsのモジュールをクライアントjsで一部動かせることがわかったのでflux?とかいうのも動かせるか確認したいと思う