LoginSignup
44
15

More than 5 years have passed since last update.

React v15.1.0 チュートリアルをReact + ES6(Babel) + Webpackで実装する

Last updated at Posted at 2016-06-11

概要

React + ES6 + Webpackでチュートリアルを行ったのでES6バージョンのソースをメモ。
【本家】 https://facebook.github.io/react/docs/tutorial.html

ES6変換ソース一覧

webpack.config.js

/webpack.config.js

let path       = require('path');
let webpack    = require('webpack');

const PATHS = {
  src: path.join(__dirname, 'src'),
  www: path.join(__dirname, 'www')
};

module.exports = {
  entry: [
    `${PATHS.src}/App.jsx`
  ],
  output: {
    path: PATHS.www,
    filename: 'bundle.js'
  },
  resolve: {
    extensions: [
      '',
      '.js',
      '.jsx'
    ]
  },
  plugins: [
    new webpack.ProvidePlugin({
      jQuery: 'jquery',
      $: 'jqeury'
    })
  ],
  devtool: 'inline-source-map',
  devServer: {
    contentBase: './www',
    port: 3000,
    hot: false,
    inline: true,
    colors: true
  },
  module: {
    loaders: [
      // Babel
      {
        test: [
          /\.jsx$/,
          /\.js$/
        ],
        loaders: [
          'babel'
        ],
        exclude: /node_modules/
      },
      // Sass
      {
        test: [
          /\.scss$/
        ],
        loaders: [
          'style',
          'css',
          'sass'
        ]
      },
      // CSS & Bootstrap
      { test: /\.css$/, loader: 'style-loader!css-loader' },
      { test: /\.svg$/, loader: 'url-loader?mimetype=image/svg+xml' },
      { test: /\.woff$/, loader: 'url-loader?mimetype=application/font-woff' },
      { test: /\.woff2$/, loader: 'url-loader?mimetype=application/font-woff' },
      { test: /\.eot$/, loader: 'url-loader?mimetype=application/font-woff' },
      { test: /\.ttf$/, loader: 'url-loader?mimetype=application/font-woff' }
    ]
  }
};

.babelrc

/.babelrc

{
  "presets": [
    "react",
    "es2015"
  ]
}

App.jsx

/src/App.jsx


/*::::::::::::::::::::::::::::::::::
 JS
:::::::::::::::::::::::::::::::::::*/
import React from 'react';
import ReactDOM from 'react-dom';

/*::::::::::::::::::::::::::::::::::
 Components
:::::::::::::::::::::::::::::::::::*/
import CommentApp from './components/Comment/CommentApp';

/*::::::::::::::::::::::::::::::::::
 InitialDOM
:::::::::::::::::::::::::::::::::::*/
let mountNode = document.getElementById('mountNode');

/*::::::::::::::::::::::::::::::::::
 AppComponent Defined
:::::::::::::::::::::::::::::::::::*/

export default class App extends React.Component {
  render() {
    return (
      <div className="container-fluid">
        <CommentApp url="http://XXXXXXXXXX/dummy/comments.json" pollInterval={2000} />
      </div>
    );
  }
}

/*::::::::::::::::::::::::::::::::::
 ToDOMRendering
:::::::::::::::::::::::::::::::::::*/
ReactDOM.render(<App />, mountNode);

CommentApp.jsx

チュートリアルではCommentBox.jsxだったがAppで統一したかった為、名称変更。

/src/components/Comment/CommentApp.jsx

import React from 'react';
import CommentList from './CommentList';
import CommentForm from './CommentForm';
import $ from 'jquery';

export default class CommentApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: [
        {
          author: 'Jack',
          text: 'just setting up my twttr'
        },
        {
          author: 'Evu',
          text: 'this tweet is nice'
        }
      ]
    };
    this.loadCommentsFromServer = this.loadCommentsFromServer.bind(this);
    this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
  }

  componentDidMount() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  }

  loadCommentsFromServer() {
    // Ajaxは一旦コメントアウトでstateベースで実装

    // $.ajax({
    //   url: this.props.url,
    //   dataType: 'json',
    //   cache: false,
    //   success: (data) => { this.setState({ data }); },
    //   error: (xhr, status, err) => {
    //     console.log(this.props.url, status, err.toString());
    //   }
    // });

    this.setState({
      data: this.state.data
    });
  }

  handleCommentSubmit(comment) {
    this.setState({
      data: this.state.data.concat(comment)
    });
  }

  render() {
    return (
      <div className="commentApp">
        <h1>CommentApp</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
}

CommentApp.propTypes = {
  data: React.PropTypes.array,
  url: React.PropTypes.string,
  pollInterval: React.PropTypes.number
};

CommentList.jsx

/src/components/Comment/CommentList.jsx

import React from 'react';
import Comment from './Comment';

export default class CommentList extends React.Component {
  render() {
    let commentNodes = this.props.data.map((comment, i) => {
      return (
        <Comment key={i} author={comment.author}>{comment.text}</Comment>
      );
    });
    return (
      <div className="commentList">
        {commentNodes}
      </div>
    );
  }
}

CommentList.propTypes = {
  data: React.PropTypes.array
};

CommentForm.jsx

/src/components/Comment/CommentForm.jsx

import React from 'react';

export default class CommentForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    // ブラウザ挙動停止
    e.preventDefault();

    // refの値を取得
    let author = this.refs.author.value;
    let text = this.refs.text.value;
    if (!text || !author) return;

    // サーバにデータを送信
    this.props.onCommentSubmit({
      author,
      text
    });

    // 値を空にする
    this.refs.author.value = '';
    this.refs.text.value = '';
  }

  render() {
    return (
      <form
        className="commentForm"
        onSubmit={this.handleSubmit}
      >
        <input
          type="text"
          placeholder="YourName"
          className="textArea"
          ref="author"
        />
        <input
          type="text"
          placeholder="Say Something..."
          ref="text"
          className="textArea"
        />
        <input
          type="submit"
          value="Tweet"
        />
      </form>
    );
  }
}

CommentForm.propTypes = {
  onCommentSubmit: React.PropTypes.func
};

Comment.jsx

/src/components/Comment/Comment.jsx

import marked from 'marked';
import React from 'react';

export default class Comment extends React.Component {

  render() {
    let rawMarkup = marked(this.props.children.toString(), { sanitize: true });
    return (
      <div className="comment">
        <h3 className="commentAuthor">
          {this.props.author}
        </h3>
        <span dangerouslySetInnerHTML={{ __html: rawMarkup }} />
      </div>
    );
  }
}

Comment.propTypes = {
  author: React.PropTypes.string,
  children: React.PropTypes.string
};

まとめ

やっぱりES6で書くと気持ちいい。
React関連の勉強をもっと進めよう。
gulpからWebpackに乗り換えたけど、設定さえ覚えればWebpackの方が便利かも。

Github

44
15
0

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
44
15