23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ReactのTutorialをArdaで写経してみる(Babel版)

Last updated at Posted at 2015-03-08

※ 3/18 arda 0.13向けにコードを修正

コーヒーはあまり好きでは…

ReactのTutorialをArdaで写経してみる
↑前々回の記事でCoffeeScriptを使ったけど、クライアント側の開発でJavaScriptを使いつつ、更にCoffeeScriptを使うのはちょっと…な人も多いか思いBabel(ES6)で書き直してみた。個人的にはCoffeeScriptでサクサク書くのも悪くはないと思うんだけどね。

Babelってなに?

Babel
なんかPC88ゲームのロゴみたいだ。

ECMAScript 6のコードを、ECMAScript 5に変換するJavaScriptトランスパイラ

以前は6to5という名前だったけど最近変わったらしい。これを使えばES6の文法を使いつつ、現状の環境で動作させることができる。やっぱ**=>とかclass**は使いたいからね。

環境設定

gulpを使うので出番はないけど、BabelのCLIをインストール。

> npm install -g babel

開発言語をCoffeeScriptからES6(Babel)へ変更するのでgulpfile.jsを修正する。

var gulp = require('gulp');
var babelify = require('babelify');
var browserify = require('browserify');
var source = require('vinyl-source-stream');

gulp.task('build', function() { 
    return browserify({ 
        entries:['./src/App.jsx'],
        extensions:['js', 'jsx']
    })
    .transform(babelify)
    .bundle() 
    .pipe(source('bundle.js')) 
    .pipe(gulp.dest('./public'));
});

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

変更箇所をみてみよう。

    return browserify({ 
        entries:['./src/App.jsx'],
        extensions:['js', 'jsx']
    })

拡張子が.jsxになっているね。言い忘れてたけど、BabelはJSXを解釈できるのでコード中に埋め込みまくった。

    .transform(babelify)

Babel(ES6)->ES5変換にbabelifyを使う。

> npm install babelify babel --save-dev

忘れずインストール。(ついでにbabelも)

準備はこんなところ。

Babelでチュートリアル開始

やってることは前回と同じなので、ぱっぱとコードを貼っていこう。

// Comment.jsx
import {mixin} from 'arda';
import md2react from 'md2react';

var Comment = React.createClass({
    mixins: [mixin],
    render() {
        return (
            <div className='comment'>
                <h2 className='commentAuthor'> 
                    {this.props.author} 
                </h2>
                { md2react(this.props.children.toString()) }
            </div>
        );
    }
});

module.exports = Comment;

arda 0.13ではコンポーネントの作成にReact.createClassを使うようになった。ES6のクラスは使わない。解説もバッサリカット

React.createElementだった箇所はJSXになってる。React本家のチュートリアルを見ていれば、こっちの方が馴染んているかも?

// CommentList.jsx
import {mixin} from 'arda';
import Comment from './Comment.jsx';

var CommentList = React.createClass({
    mixins: [mixin],

    render() {
        let commentNodes = this.props.data.map((comment) => (
                    <Comment author={comment.author}>
                        {comment.text}
                    </Comment>
                )
        ); 

        return (
                <div className='commentList'> 
                    {commentNodes} 
                </div>
        );
    }
});

module.exports = CommentList;

解説が必要なところはないかな。

/// CommentForm.jsx
import {mixin} from 'arda';

var CommentForm = React.createClass({
    mixins: [mixin],
    render() {
        return (
                <form className='commentForm' onSubmit={this.handleSubmit.bind(this)}>
                    <input type='text' placeholder='Your name' ref='author'/>
                    <input type='text' placeholder='Say something...' ref='text'/>
                    <input type='submit' value='Post'/>
               </form>
        );
    },

    handleSubmit(e) {
        e.preventDefault();
        let author = React.findDOMNode(this.refs.author).value.trim();
        let text = React.findDOMNode(this.refs.text).value.trim();
        if (!author || !text)
            return;

        this.dispatch('commentSubmit', {author, text});

        React.findDOMNode(this.refs.author).value = '';
        React.findDOMNode(this.refs.text).value = '';
    }

});

module.exports = CommentForm;

これもあまり変わらず。ただ、ここに注目。

{author, text}

ES6では、下記のように書かなくてもよくなった。

{
    author: author,
    text: text
}
// CommentBox.jsx
import {mixin} from 'arda';
import CommentList from './CommentList.jsx';
import CommentForm from './CommentForm.jsx';

var CommentBox = React.createClass({
    mixins: [mixin],
    render() {
        return (
            <div className='commentBox'>
                <h1>Comments</h1>
                <CommentList data={this.props.data} />
                <CommentForm />
            </div>
      );
    }

});

module.exports = CommentBox;

説明はいらないかな。

// App.jsx
window.React = require('react');
window.Promise = require('bluebird');
window.ReactBootstrap = require('react-bootstrap');
import {Context, Router, DefaultLayout, mixin} from 'arda';
import CommentBox from './CommentBox.jsx';
import request from 'superagent';

var App = React.createClass({
    mixins: [mixin],
    render() {
        return (
                <div>
                    <CommentBox data={ this.props.data } />
                </div>
        );
    }
});

class AppContext extends Context {
    get component() {
        return App;
    }

    initState() { return { data:[] }; }

    expandComponentProps(props, state) { return { data: state.data}; }

    loadCommentsFromServer() {
        request
            .get(this.props.url)
            .set({Accept:'application/json'})
            .end((res)=> this.update( ()=> { return {data:res.body}; }) );
    }

    delegate(subscribe) {
        super.delegate();

        subscribe('context:started', ()=> {
            this.loadCommentsFromServer();
            setInterval(()=>this.loadCommentsFromServer(), this.props.pollInterval);
        });

        subscribe('commentSubmit', (comment) => {
            request
                .post(this.props.url)
                .send(comment)
                .set({Accept:'application/json'})
                .end((err, res) => { /* 最新のsuperagentでは第一引数にerrが必要 */
                    if (res.ok) {
                        this.update( (s)=> { 
                            return {data:s.data.concat([res.body])};
                        });
                    } else {
                        console.log(res.text);
                    }
                });
        });
    }
}

window.addEventListener('DOMContentLoaded', ()=> {
    let router = new Router(DefaultLayout, document.body);
    router.pushContext(AppContext, {url:'/comments.json', pollInterval:2000});
});

コンテキストはclassを使えるのでContextから継承。

これで完成。

> gulp

を叩いて、json-serverを起動すれば動くはず。

まとめ

クライアント側のコードをサクサク書きたいけど、そのために別の言語を使うのはちょっと…なら、Babelを使ってみるのもありかも。

TypeScriptを使ってもよいとは思うんだけど、画面回りは型よりも手軽さの方が嬉しいかなっと。

23
23
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?