初めてのXHP Tutorial / XHPとReact

# XHPをやってみよう！
今回はReactのTutorialで使われているものを、HackのXHPを利用して、その差を紹介します。
JSのコード(Reactなど)を吐き出す訳ではありませんので、
onClickなどのインタラクティブな要素はなく、
あくまで描画のみとなります。

## ShoppingList
Reactのチュートリアルの概要で紹介されている例です。
JSXの例です。

```jsx
class ShoppingList extends React.Component {
  render() {
    return (
      <div className="shopping-list">
        <h1>Shopping List for {this.props.name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>
    );
  }
}

```

これをXHPとして記述します。

```hack
<?hh // strict

class :ShoppingList extends :x:element {
  attribute string name @required;
  protected function render(): \XHPRoot {
    return <div class="shopping-list\">
        <h1>Shopping List for {$this->:name}</h1>
        <ul>
          <li>Instagram</li>
          <li>WhatsApp</li>
          <li>Oculus</li>
        </ul>
      </div>;
  }
}

```

PHPに慣れているとcomposer.jsonでPSR-4を利用しているため、
ディレクトリ、ファイル名を合わせる必要がありますが、
Hackの場合は [hhvm/hhvm-autoload](https://github.com/hhvm/hhvm-autoload) を利用して、
XHP関係のものはオートローダーが吸収しますので、意識する必要はありません。
また、一ファイルに複数のXHPクラスが存在していても問題ありませんので、
Reactと同じ感覚で実装します。

描画は下記で行います。

```hack
<?hh // strict

require __DIR__ .'/vendor/hh_autoload.php';

<<__Entrypoint>>
function run(): void {
  echo <ShoppingList name="ytake"/>;
}

```

出力結果はこの通りです。

<img width="421" alt="スクリーンショット 2018-12-09 23.04.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/32814/40872854-5780-6bb4-646b-d5d17707792e.png">

JSでの操作などを行う訳ではないためclassNameなどはありませんが、
基本的なところはほぼ同等というのがわかると思います。
Attributeの記述方法は次の通りです。

```
attribute <type> <name> [= default value|@required];
```

Attributeなど、Hackに対応しているIDEでは基本的にすべて補完等できますので、
簡単に理解できると思います。

XHPはasyncを使って描画などを行うことはできますが、あくまでI/Oが発生するものに対してとなりますので、
利用ケースとしてはHTTPリクエストや、DBの処理などと組み合わせます。

同じ出力結果になりますが、下記の様に記述することもできます。

```hack
<?hh // strict

require __DIR__ .'/vendor/hh_autoload.php';

<<__Entrypoint>>
function run(): void {
  $div = <div />;
  $div->addClass('shopping-list');
  $name = 'ytake';
  $header = <h1>Shopping List for {$name}</h1>;
  $div->appendChild($header);
  $list = <ul />;
  $v = vec['Instagram', 'WhatsApp', 'Oculus'];
  foreach ($v as $item) {
    $list->appendChild(<li>{$item}</li>);
  }
  $div->appendChild($list);
  echo $div;
}

```

ほとんどの場合では後者で記述することはないと思います。

## tic-tac-toe / 三目並べ
次に三目並べですが、XHPでは描画までとなりますので、
描画部分のみをXHPで記述してみましょう。
Reactの例と同じ様に下記の三つのコンポーネントを用意します。

 - Square
 - Board
 - Game

### Square
JSXでの記述は次の通りです。

```jsx
class Square extends React.Component {
  render() {
    return (
      <button className="square">
        {this.props.value}
      </button>
    );
  }
}

```

XHPで記述してもそこまで大差はありません。
ここでは描画部分のみを記述しますので、valueは必須にしておきましょう。

```hack
<?hh // strict

class :Square extends :x:element {
  attribute int value @required;
  protected function render(): \XHPRoot {
    return <button class="square">
        {$this->:value}
      </button>;
  }
}

```

### Board
次にboardです。

```jsx
class Board extends React.Component {
  renderSquare(i) {
    return <Square value={i} />;
  }

  render() {
    const status = 'Next player: X';

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

```

これに対してXHPです。
これもそこまで大きな差はありません。

```hack
class :Board extends:x:element {
  const string STATUS = 'Next player: XHP';

  private function renderSquare(int $i): :Square {
    return <Square value={$i} />;
  }

  protected function render(): \XHPRoot {
    return <div>
        <div class="status">{self::STATUS}</div>
        <div class="board-row">
          {$this->renderSquare(0)}
          {$this->renderSquare(1)}
          {$this->renderSquare(2)}
        </div>
        <div class="board-row">
          {$this->renderSquare(3)}
          {$this->renderSquare(4)}
          {$this->renderSquare(5)}
        </div>
        <div class="board-row">
          {$this->renderSquare(6)}
          {$this->renderSquare(7)}
          {$this->renderSquare(8)}
        </div>
      </div>;
  }
}

```

### Game
最後にGameです。
まずはjsxの例です。

```jsx
class Game extends React.Component {
  render() {
    return (
      <div className="game">
        <div className="game-board">
          <Board />
        </div>
        <div className="game-info">
          <div>{/* status */}</div>
          <ol>{/* TODO */}</ol>
        </div>
      </div>
    );
  }
}

```

特に難しいものはありません。

```hack
class :Game extends :x:element {
  protected function render(): \XHPRoot {
    return <div class="game">
        <div class="game-board">
          <Board />
        </div>
        <div class="game-info">
          <div></div>
          <ol></ol>
        </div>
      </div>;
  }
}

```

これらを出力すると以下のものになります。
Reactのサンプルと全く同じものです。

<img width="137" alt="スクリーンショット 2018-12-10 0.05.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/32814/3464a283-a9e0-9bfb-75ec-7b7e113d4099.png">

ボタンのonclickにイベントを埋める場合は、
前回紹介したXHPUnsafeRenderableを実装したクラスを利用します。

```hack
final class ClickAlert implements XHPUnsafeRenderable {
  public function toHTMLString(): string {
    return "alert('click');";
  }
}

```

作成したクラスを `:Square` クラスで利用します。

```hack
class :Square extends :x:element {
  attribute int value @required;
  protected function render(): \XHPRoot {
    $stringish = new ClickAlert()|> $$->toHTMLString();
    return <button class="square" onclick={$stringish}>
        {$this->:value}
      </button>;
  }
}

```

描画までのコードは以下の通りです。

```hack
<?hh // strict

class :Square extends :x:element {
  attribute int value @required;
  protected function render(): \XHPRoot {
    $stringish = new ClickAlert()|> $$->toHTMLString();
    return <button class="square" onclick={$stringish}>
        {$this->:value}
      </button>;
  }
}

class :Board extends:x:element {
  const string STATUS = 'Next player: XHP';

  private function renderSquare(int $i): :Square {
    return <Square value={$i} />;
  }

  protected function render(): \XHPRoot {
    return <div>
        <div class="status">{self::STATUS}</div>
        <div class="board-row">
          {$this->renderSquare(0)}
          {$this->renderSquare(1)}
          {$this->renderSquare(2)}
        </div>
        <div class="board-row">
          {$this->renderSquare(3)}
          {$this->renderSquare(4)}
          {$this->renderSquare(5)}
        </div>
        <div class="board-row">
          {$this->renderSquare(6)}
          {$this->renderSquare(7)}
          {$this->renderSquare(8)}
        </div>
      </div>;
  }
}

class :Game extends :x:element {
  protected function render(): \XHPRoot {
    return <div class="game">
        <div class="game-board">
          <Board />
        </div>
        <div class="game-info">
          <div></div>
          <ol></ol>
        </div>
      </div>;
  }
}

final class ClickAlert implements XHPUnsafeRenderable {
  public function toHTMLString(): string {
    return "alert('click');";
  }
}

```

最後のEntrypoiintでの出力は下記のもののみです。

```hack
<?hh // strict

require __DIR__ .'/vendor/hh_autoload.php';

<<__Entrypoint>>
function run(): void {
  echo <Game />;
}

```

基本的な実装方法を覚えて、ぜひ活用してみてください。