Help us understand the problem. What is going on with this article?

React TutorialをES2015で書いた時のメモ

More than 3 years have passed since last update.

React TutorialをES2015で書いた時のメモ。

コンポーネントの構造は以下。

- CommentBox
  - CommentList
    - Comment
  - CommentForm

準備

いろいろとnpm installした結果のpackage.json

package.json
{
  "scripts": {
    "build": "webpack"
  },
  "devDependencies": {
    "babel-cli": "^6.9.0",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.9.0",
    "babel-preset-react": "^6.5.0",
    "webpack": "^1.13.1"
  },
  "dependencies": {
    "marked": "^0.3.5",
    "react": "^15.1.0",
    "react-dom": "^15.1.0",
    "superagent": "^1.8.3"
  }
}

webpackでビルドするので、そちらの設定も。

webpack.config.babel.js
import path from 'path';

const src = path.resolve(__dirname, 'src');
const dist = path.resolve(__dirname, 'dist');

export default {
  entry: `${src}/app.js`,

  output: {
    path: dist,
    filename: 'bundle.js'
  },

  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        include: [src],
        loader: 'babel'
      }
    ]
  }
};

ES2015 + React で記述

jsを読み込むHTMLを用意。

index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>React Tutorial</title>
  </head>
  <body>
    <div id="container"></div>
    <script src="./dist/bundle.js"></script>
  </body>
</html>

一番上のレイヤーのCommentBoxコンポーネントをrenderするjs。Webpackの設定にも書いたように、このファイルをトランスパイルすることになる。

src/app.js
import React from 'react';
import { render } from 'react-dom';
import CommentBox from './components/CommentBox';

render(
  <CommentBox url="http://localhost:4567/api/comments" pollInterval={2000} />,
  document.getElementById('container')
);

各コンポーネントの記述。
class記法を使ってコンポーネントを作成。

src/components/CommentBox.js
import React from 'react';
import request from 'superagent';
import CommentList from './CommentList';
import CommentForm from './CommentForm';

export default class CommentBox extends React.Component {
  constructor(props) {
    super(props);
    this.state = {data: []};

    this.loadCommentsFromServer = this.loadCommentsFromServer.bind(this);
    this.handleCommentSubmit = this.handleCommentSubmit.bind(this);
  }
  loadCommentsFromServer () {
    request
      .get(this.props.url)
      .end((error, response) =>
        this.setState({data: JSON.parse(response.text)}));
  }
  handleCommentSubmit(comment) {
    const comments = this.state.data;
    comment.id = Date.now();
    const newComments = [...comments, comment];
    this.setState({data: newComments});

    request
      .post(this.props.url)
      .send(comment)
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .end((error, response) => {
        if (error !== null) {
          this.setState({data: comments});
        } else {
          this.setState({data: JSON.parse(response.text)});
        }
      });
  }
  componentDidMount() {
    this.loadCommentsFromServer();
    setInterval(this.loadCommentsFromServer, this.props.pollInterval);
  }
  render() {
    return (
      <div className="commentBox">
        <h1>Comments</h1>
        <CommentList data={this.state.data} />
        <CommentForm onCommentSubmit={this.handleCommentSubmit} />
      </div>
    );
  }
}
src/components/CommentList.js
import React from 'react';
import Comment from './Comment';

export default class CommentList extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    const commentNodes = this.props.data.map((comment) =>
      <Comment author={comment.author} key={comment.id}>{comment.text}</Comment>);
    return (
      <div className="commentList">{commentNodes}</div>
    );
  }
}
src/components/Comment.js
import React from 'react';
import marked from 'marked';

export default class Comment extends React.Component {
  constructor(props) {
    super(props);
  }
  rawMarkup() {
    const rawMarkup = marked(this.props.children.toString(), {sanitize: true});
    return { __html: rawMarkup };
  }
  render() {
    return (
      <div className="comment">
        <h2 className="commentAuthor">
          {this.props.author}
        </h2>
        <span dangerouslySetInnerHTML={this.rawMarkup()} />
      </div>
    );
  }
}
src/components/CommentForm.js
import React from 'react';

export default class CommentForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      'author': '',
      'text': ''
    };

    this.handleAuthorChange = this.handleAuthorChange.bind(this);
    this.handleTextChange = this.handleTextChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleAuthorChange(e) {
    this.setState({author: e.target.value});
  }
  handleTextChange(e) {
    this.setState({text: e.target.value});
  }
  handleSubmit(e) {
    e.preventDefault();
    const author = this.state.author.trim();
    const text = this.state.text.trim();
    if (!text || !author) {
      return;
    }
    this.props.onCommentSubmit({author: author, text: text});
    this.setState({
      'author': '',
      'text': ''
    });
  }
  render() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input
          type="text"
          placeholder="Your name"
          value={this.state.author}
          onChange={this.handleAuthorChange}
        />
        <input
          type="text"
          placeholder="Say something..."
          value={this.state.text}
          onChange={this.handleTextChange}
        />
        <input type="submit" value="Post" />
      </form>
    );
  }
}

これで終わり。
npm run buildすると、トランスパイルされたdist/bundle.jsが生成されるので、それをHTMLで読み込む。

※サーバサイド

RubyのSinatraで、非常に雑な実装のやつを書いた。

Gemfile
gem 'sinatra'
gem 'sinatra-contrib'
app.rb
require 'sinatra'
require 'sinatra/reloader' if development?
require 'json'

response_body = [
  { id: 1,
    author: "Peter Hunt",
    text: "This is one comment"
  },
  {
    id: 2,
    author: "Jordan Walke",
    text: "This is *another* comment"
  }
]

get '/api/comments' do
  headers 'Access-Control-Allow-Origin' => '*'
  body response_body.to_json
end

post '/api/comments' do
  response_body << {
    id: response_body.last[:id] + 1,
    author: params["author"],
    text: params["text"]
  }

  headers 'Access-Control-Allow-Origin' => '*'
  body response_body.to_json
end

ruby app.rbを実行するとhttp://localhost:4567で開発サーバが起動し、APIにアクセス可能になる。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした