LoginSignup
10
10

More than 5 years have passed since last update.

Reactのコードをやっと理解した私が、文法や動作を無視して更に分かりやすく書いてみる

Last updated at Posted at 2014-12-31

注意

  • 本投稿は一種のネタであり、Afterのコードは動作しません
  • 本投稿の著者はReactを使ったことはありません。

概要

本投稿では、JSX記法でも読みにくい(と私は感じている)Reactのサンプルコードを、
直感的に理解できるよう、分かりにくい箇所を場合によってはJavaScriptの文法・動作を無視したコードに書き直してみます。

書きなおしたコードは私の主観で書かれているので、人によっては読みにくいかもしれません。

サンプル

Reactのサンプルコードは、公式サイトより引用します。
A JavaScript library for building user interfaces | React

A Stateful Component

Before
var Timer = React.createClass({
  getInitialState: function() {
    return {secondsElapsed: 0};
  },
  tick: function() {
    this.setState({secondsElapsed: this.state.secondsElapsed + 1});
  },
  componentDidMount: function() {
    this.interval = setInterval(this.tick, 1000);
  },
  componentWillUnmount: function() {
    clearInterval(this.interval);
  },
  render: function() {
    return (
      <div>Seconds Elapsed: {this.state.secondsElapsed}</div>
    );
  }
});

React.render(<Timer />, mountNode);

After
/**
 * Timer要素を作成する
 */
Timer = React.createClass(
    function getInitialState() {
        /**
         * this.state に初期値を設定する
         */
        this.state.secondsElapsed = 0;
    }

    function this.tick() {
        /**
         * this.state.secondsElapsed の値を1増やす
         */
        this.state.secondsElapsed = this.state.secondsElapsed + 1;
    }

    function componentDidMount() {
        /**
         * Timer要素がDOMに追加されたら、
         * タイマーを起動し、
         * 1秒毎に this.tick 関数を呼ぶ
         */
        this.interval = setInterval(this.tick, 1000);
    }

    function componentWillUnmount() {
        /**
         * Timer要素がDOMから削除されたら、
         * タイマーを停止する
         */
        clearInterval(this.interval);
    }

    return <div>Seconds Elapsed: {this.state.secondsElapsed}</div>;
);

React.render(<Timer />, mountNode);

コメントを追加し、
this.setState関数を変数代入に変えました。
あとrender関数は省略しています。

これだけで随分と見やすくなったと思いますがいかがでしょう?
少なくとも私は読みやすいです。

以下もこの調子でいきます。

An Application

Before
var TodoList = React.createClass({
  render: function() {
    var createItem = function(itemText) {
      return <li>{itemText}</li>;
    };
    return <ul>{this.props.items.map(createItem)}</ul>;
  }
});
var TodoApp = React.createClass({
  getInitialState: function() {
    return {items: [], text: ''};
  },
  onChange: function(e) {
    this.setState({text: e.target.value});
  },
  handleSubmit: function(e) {
    e.preventDefault();
    var nextItems = this.state.items.concat([this.state.text]);
    var nextText = '';
    this.setState({items: nextItems, text: nextText});
  },
  render: function() {
    return (
      <div>
        <h3>TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <input onChange={this.onChange} value={this.state.text} />
          <button>{'Add #' + (this.state.items.length + 1)}</button>
        </form>
      </div>
    );
  }
});

React.render(<TodoApp />, mountNode);

After
/**
 * TodoList要素を作成する
 */
TodoList = React.createClass(
    /**
     * items属性の値を取得する
     * items属性には配列が指定される
     */
    items = this.props.items;

    function createItem(itemText) {
        return <li>{itemText}</li>;
    }

    /**
     * items属性に指定した配列の各値を含むli要素を含む
     * ul要素を作成する
     */
    return <ul>{items.map(createItem)}</ul>;
);

/**
 * TodoApp要素を作成する
 */
TodoApp = React.createClass({
    function getInitialState() {
        /**
         * this.state に初期値を設定する
         */
        this.state.items = [];
        this.state.text = '';
    }

    function this.onChange(e) {
        /**
         * input要素の入力値が変更されたら、
         * this.state.text に入力値を代入する
         */
        this.state.text = e.target.value;
    }

    function this.handleSubmit(e) {
        /**
         * 項目を追加しようとしたら(フォームが送信されそうになったら)、
         * 配列 this.state.items に文字列 this.state.text を追加する
         */
        e.preventDefault();

        var nextItems = this.state.items.concat([this.state.text]);
        var nextText = '';

        this.state.items = nextItems;
        this.state.text = nextText;
    }

    return (
        <div>
            <h3>TODO</h3>
            <TodoList items={this.state.items} />
            <form onSubmit={this.handleSubmit}>
                <input onChange={this.onChange} value={this.state.text} />
                <button>Add #{this.state.items.length + 1}</button>
            </form>
        </div>
    );
});

React.render(<TodoApp />, mountNode);

A Component Using External Plugins

Before
var converter = new Showdown.converter();

var MarkdownEditor = React.createClass({
  getInitialState: function() {
    return {value: 'Type some *markdown* here!'};
  },
  handleChange: function() {
    this.setState({value: this.refs.textarea.getDOMNode().value});
  },
  render: function() {
    return (
      <div className="MarkdownEditor">
        <h3>Input</h3>
        <textarea
          onChange={this.handleChange}
          ref="textarea"
          defaultValue={this.state.value} />
        <h3>Output</h3>
        <div
          className="content"
          dangerouslySetInnerHTML={{
            __html: converter.makeHtml(this.state.value)
          }}
        />
      </div>
    );
  }
});

React.render(<MarkdownEditor />, mountNode);

After
converter = new Showdown.converter();

/**
 * MarkdownEditor要素を作成する
 */
MarkdownEditor = React.createComponent({
    function getInitialState() {
        /**
         * this.state に初期値を設定する
         */
        this.state.value = 'Type some *markdown* here!';
    }

    function this.handleChange() {
        /**
         * textarea要素の入力値が変更されたら、
         * this.state.value に入力値を代入する
         */
        textarea = this.refs.textarea.getDOMNode();

        this.state.value = textarea.value;
    }

    return (
        <div className="MarkdownEditor">
            <h3>Input</h3>
            <textarea onChange={this.handleChange} ref="textarea" defaultValue={this.state.value}>
            <h3>Output</h3>
            <div className="content">{html: converter.makeHtml(this.state.value)}</div>
        </div>
    );
});

React.render(<MarkdownEditor />, mountNode);

dangerouslySetInnerHTMLって分かりにくいので、省略してみます。
動作は前提としないので、多少矛盾があっても問題ないよね?

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