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

## 注意

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

## 概要

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

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

## サンプル

Reactのサンプルコードは、公式サイトより引用します。
[A JavaScript library for building user interfaces | React](http://facebook.github.io/react/)

### A Stateful Component

```txt: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);
```

↓

```txt: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

```txt: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);
```

↓

```txt: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

```txt: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);
```

↓

```txt: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`って分かりにくいので、省略してみます。
動作は前提としないので、多少矛盾があっても問題ないよね?