LoginSignup
1
1

More than 5 years have passed since last update.

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

Posted at

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にアクセス可能になる。

1
1
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
1
1