ReactユーザーのためのAngular2ファーストステップ

Reactはやったことある人向けに、ReactのアレはAngular2だとどうなってるの？というのをまとめていきます。Reactユーザーだった自分がAngular2始めるにあたりこういう情報あればなと思ってたやつです :joy:

ところでAngular2じゃなくてAngularと呼んでね！とのことなので、以下Angularと呼びますがAngular 2.xを指します。

# アプリケーションのブートストラップ

**React**

```html:index.html
<!doctype html>
<html lang="en">
  <head>
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>
```

```:index.js
import React from 'react';
import ReactDOM from 'react-dom';

class App extends Component {
  render() {
    return (
      <div>
        <p>hello world</p>
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);
```

ReactではアプリケーションのルートとなるComponentと、対象となるDOM要素を指定して `ReactDOM.render` ですね。

**Angular**

```html:index.html
<!doctype html>
<html>
<head>
  <title>Angular2</title>
</head>
<body>
  <app-root>Loading...</app-root>
</body>
</html>
```

```:index.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
```

```:app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

```:app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <p>{{title}}</p>
    </div>
  `
})
export class AppComponent {
  title = 'hello world';
}
```

Angularでは、ブートストラップ対象になるのはModuleです。Moduleは、Component、Serviceなどからなるアプリケーションの機能の単位です。 `@NgModule` デコレータの `bootstrap` に指定したComponentが表示されます。
この例では `platformBrowserDynamic().bootstrapModule(AppModule);` で `AppModule` が起動し、 `bootstrap: [AppComponent]` なので `AppComponent` 描画され、 `selector: 'app-root'` なので `<app-root>Loading...</app-root>` が `<div><p>hello world</p></div>` に書き換わるという感じです！

# Component

**React**

```:App.js
class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      todos: [
        'sleep',
        'do nothing'
      ]
    };
  }

  componentDidMount() {
    console.log('mounted :)');
  }

  render() {
    return (
      <div className="App">
        <h1>{this.props.title}</h1>
        <ul>
          {this.state.todos.map((todo, i) => <li key={i}><p>{todo}</p></li>)}
        </ul>
        <button type="button" onClick={this.props.onClick}> +1 :)</button>
        { this.props.children }
      </div>
    );
  }
}
```

`React.Component` を継承したクラスに `render` メソッドを実装しておけばReactのComponentですね！
その他にも `componentDidMount` などのライフサイクルメソッド、 `props`,  `props.children`, `state` あたりがReact Componentの代表的な機能でしょうか。

**Angular**

先程の例にもあるように、AngularではReactで `render` メソッドに書いていたHTMLは `@Component` デコレータに書きます。 `templateUrl: 'app.component.html'` とすることでHTMLファイルを分離することもできます。CSSも同様です。
Reactだとクラス名がそのまま `<MyClass />` のように使えましたが、Angularでは `selector` に指定した文字列がそのComponentで置き換えられます。
Reactの `props`, `props.children`,  `state`, ライフサイクルメソッドに相当するような機能がAngularにもあるので、ひとつずつ見ていきましょう。

# props

```:app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <sample-child [title]="'hello'" (onHello)="handleHello($event)"></sample-child>
  `
})
export class AppComponent {
  handleHello(ev: any) {
    console.log(ev);
  }
}
```

```:sample-child.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'sample-child',
  template: `
    <h1>{{title}}</h1>
    <button type="button" (click)="clicked()">say hello</button>
  `
})
export class SampleChildComponent {
  @Input() title: string;
  @Output() onHello = new EventEmitter<any>();

  clicked() {
    this.onHello.emit({ 'i said': 'hello' });
  }
}
```

## 親Component→子Component

親Componentから子Componentにデータを受け渡すには、子Componentに `@Input` アノテーションを付けたプロパティを用意します。親Componentは `<child [title]="'hello'" />` のように `[]` で渡すプロパティを指定します。これがプロパティバインディングです。

> `<child [title]="'hello'" />` の `"'hello'"` という表記が気になったかと思いますが、これはReactでいう `<Child title={'hello'} />` です。Reactだと `{}` の中にJSの式を書けるように、Angularのバインディングの右辺では `""` の中はJSになります。　なのでただの文字列を与えたいときは `"'hello'"` となります。

## 子Component→親Component

子から親にイベントを伝えるには、子に `@Output() onHello = new EventEmitter<any>();` のように `@Output` アノテーションをもった `EventEmitter` のプロパティを定義し、親では `<child (onHello)="handleHello($event)" />` のように `()` で囲んで指定します。 `handleHello` は親Componentのクラスが持っているメソッドです。 `$event` は特別なシンボルで、イベントのメッセージというかペイロードが入っています。この例では `{ 'i said': 'hello' }` というJSONが入っています。これがイベントバインディングです。
他にもフォームなどでよく使う `<input [(ngModel)]="myName" />` とするTwo-wayデータバインディングなどがあります。親→子、子→親両方あるので `[(ngModel)]` ってことですかね。なかなか慣れてないとアレな気はします :sob: 

# props.children

```:app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <my-frame>
      <p>in my frame :)</p>
    </my-frame>
  `
})
export class AppComponent {
}
```

```:my-frame.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-frame',
  template: `
    <div class="myframe">
      <ng-content></ng-content>
    </div>
  `,
  styles: [`
    .myframe {
      color: red;
    }
  `]
})
export class MyFrameComponent {
}
```

自分のタグ内に定義されたHTMLを出力するには `<ng-content></ng-content>`　を使います。上記の例の出力は

```html
<div class="myframe">
  <p>in my frame :)</p>
</div>
```

となり、 `.myframe` のCSSが効いて赤い文字になります。

## state

Angularだと普通にクラス内のインスタンスをOne-wayなりTwo-wayバインディングする感じでしょうか。特に言うことないです。 :rolling_eyes:

## ライフサイクルメソッド

```:.app.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subscription } from 'rxjs';
import { SampleService } from './sample.service';

@Component({
  selector: 'app-root',
  template: `
    <p>{{message}}<p>
    <button (click)="fetchMessage()">fetch</button>
  `,
  providers: [
    SampleService
  ]
})
export class LifeCycleSampleComponent implements OnInit, OnDestroy {

  message: string = 'initial message';
  subscription: Subscription;

  constructor(private sampleService: SampleService) { }

  fetchMessage() {
    this.sampleService.nextMessage();
  }

  ngOnInit() {
    this.subscription = this.sampleService.message.subscribe(message => this.message = message);
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}
```

Reactの `componentDidMount` や `ComponentWillUnmount` といったライフサイクルメソッドに相当するものがAngularにもあります。それらを実装する場合は `class MyComponent extends OnInit` のように該当するサイクルをミックスインし、 `ngOnInit` メソッドなどに実装を書きます。実装するライフサイクルメソッドがクラスを見たときに明示的なのがいいですね！
この例ではComponentの初期化時にServiceクラス(後述)が持っているObservableをsubscribeし、Componentが破棄されるタイミングでsubscriptionも破棄しています。こういったイベントリスナーの登録・破棄がまずは思いつくユースケースな気がします。

## (Reactにはない)Service

```:sample.service.ts
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';

@Injectable()
export class SampleService {

  private _message: Subject<string>;
  message: Observable<string>;

  constructor() {
    this._message = new Subject<string>();
    this.message = this._message.asObservable();
  }

  nextMessage() {
    this._message.next('next message');
  }
}
```

Viewだけを扱うReactにはビジネスロジックや副作用などを書く場所がありません。そこでFluxアーキテクチャを導入することが多いと思います。Angularではそういったものを担当するクラスをServiceとして定義し、Componentから使うことができます。Serviceにデータを持たせて、取得や変更するメソッド、もしくはデータ変更で発火するイベントやObservableを生やしておく感じです。
Serviceのインスタンス化は自分でnewせずにAngularのも持つDIの仕組みに任せます。 `@Injectable` アノテーションを付け、Serviceを使うComponentやModuleから `providers: [ MySerivce ]` とします。そうしてコンストラクタの引数にServiceを引数として与えればServiceのインスタンスが得られます。
注意点としては `providers` に書くたびに別のServiceのインスタンスができるので、アプリケーションで共通のデータを持たせたいServiceはComponentではなくアプリケーションのModuleのprovidersに書いておかないといけません。

# router

**React**

```:index.js
// github.com/ReactTraining/react-router/README.md から
render((
  <Router history={browserHistory}>
    <Route path="/" component={App}>
      <Route path="about" component={About}/>
      <Route path="users" component={Users}>
        <Route path="/user/:userId" component={User}/>
      </Route>
      <Route path="*" component={NoMatch}/>
    </Route>
  </Router>
), document.getElementById('root'))
```

React自体はルーティングの機能を持っていないので、react-routerといったライブラリを使用すると思います。使い方はシンプルで、　`path` と `component` を列挙していく感じですね。

```diff:app.module.ts
+ import { RouterModule } from '@angular/router';
+ import { routes } from './app.routes';


@NgModule({
  ...
  imports: [
    HttpModule,
+   RouterModule.forRoot(routes)
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

```ts:app.routes.ts
import { Routes } from '@angular/router';

import { TodosComponent } from './todos/todos.component';
import { UsersComponent } from './users/users.component';

export const routes: Routes = [
  { path: 'todos', component: TodosComponent },
  { path: 'users', component: UsersComponent }
];
```

```:app.component.ts
import { Component } from '@angular/core';
@Component({
  selector: 'my-app',
  template: `
     <h1>{{title}}</h1>
     <a routerLink="/todos">Todos</a>
     <a routerLink="/users">Users</a>
     <router-outlet></router-outlet>
   `
})
export class AppComponent {
  title = 'root component';
}
```

Angularはルーティング機能も持っており、 `@angular/router` からModuleをインポートして使います。ルーティングの定義はreact-routerと似た感じでパスをComponentを書いていきます。ルーティングにマッチしたComponentは `<router-outlet></router-outlet>` に描画されます。

12/9に東京で開催された[Angularのミートアップ](https://ngjapan.connpass.com/event/44765/)では、 `@angular/core` が2.xなのに対し `@angular/router` が3.xとずれている問題があり、これを解消するために次期Angularのメジャーバージョンは３ではなく4になる話が出たみたいです([発表資料](https://docs.google.com/presentation/d/1ZpYKmq4oZhddxmE2rEoTefA2p8CXFuQqYs2VaFUUD7M/edit#slide=id.p))。4...！

# create-react-app

create-react-appと同様のツールとして[angular-cli](https://github.com/angular/angular-cli)があります。Typescript, Webpack, karmaなどなどの設定を済ませたAngularアプリの雛形を生成してくれます。それだけでなく、ComponentやServiceの雛形とそのテストコードを生成し、NgModuleにインポートしておいてくれるという便利機能なども付いています。

```sh
$ npm i -g angular-cli # ng コマンドが使えるようになる
$ ng new my-angular-app # Angularアプリを生成する
$ cd my-angular-app
$ ng serve # webpack-dev-serverを起動
$ ng test
$ ng e2e
$ ng build
$ ng g component my-component # generateを省略してg
installing component
  create src/app/my-component/my-component.component.css
  create src/app/my-component/my-component.component.html
  create src/app/my-component/my-component.component.spec.ts
  create src/app/my-component/my-component.component.ts
$ ng g service my-service
installing service
  create src/app/my-service.service.spec.ts
  create src/app/my-service.service.ts
  WARNING Service is generated but not provided, it must be provided to be used
```

個人的にWebpackとかの設定つらいので、そういったところをこういうツールで補ってもらえるのはとてもありがたいです :pray:

# react-native

Reactに対するReact Nativeと同じような位置にionic2、OnsenUI、NativeScriptなどいくつかのライブラリがあります。[angular/react-native-renderer](https://github.com/angular/react-native-renderer)というReact NativeのレンダラとAngularをつなぐ(!?)のもあるみたいです。
この中でionic2を少し触ったのですが、ionic2が提供するComponentがWeb/iOS/Androidで動作するようになっており、learn once write anywhereではなくwrite once run anywhereなとこが衝撃的でした。ジャバか...!

```
// どのプラットフォームでも動く
<ion-list>
  <button ion-item *ngFor="let item of items" (click)="itemSelected(item)">
    <my-item>{{ item }}</my-item>
  </button>  
</ion-list>
```

# 番外編

Angularへの苦手意識、解消します :muscle:

## ng-xxxを無限に覚えるのが嫌だ

Angular 1.xをちょっとやってたときの個人的な記憶なのですが、何をするにもng-xxxを使わなければならず、ng-xxxを探して実装してバグったらエラーメッセージに出て来るng-xxxがどうしたというのをググる...という辛いものがあったのですが、Angular2ではそのへんかなり軽減されてる気がします。とりあえずの登場人物は `ng-for` と `ng-if` だけで、エラーメッセージも良くなっていて、だいたいは書いてあることを読めば修正できる感じです :thumbsup: 

## JSXをキモイと言うが、 クラスにくっついてるクッソでかいデコレータにしかもtemplateがただの文字列で入ってるとかそっちのほうが（略

テンプレートがただの文字列なのは仕方ないのですが、webstormやエクステンションを入れたVSCodeなどではシンタックスハイライトを提供してくれるのでかなり低減されます。

<img width="498" alt="スクリーンショット 2016-12-14 23.36.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/59312/e732581c-fcaf-f026-7876-da212aa1eacb.png">

もちろん `templateUrl: 'foo.component.html'` としてファイルを分けてしまうのもアリです。テンプレートがただの文字列のため、実行するまではテンプレートにミスがあるかわからないという問題があります。そのためコンポーネントが描画されるかの最低限のテストを書いていくか、AoTコンパイルを行って実行前にエラーを出すなどをやったほうがいいみたいです。（そもそもAoTは必須という話も）


# まとめ

Reactから見たAngularの基礎要素をざっと紹介しました。Angular本体はstableになりましたがまだまだエコシステムがReactのように成熟していないので、いまのところは `dependencies` の中がbetaだらけになったりする難点がありますが、Webアプリを楽しく書けるフレームワークなので、まだ触っていない方は是非！ :joy:

# 参考
公式ドキュメントをGoogle翻訳片手に読んでいくのがAngular入門には結局のところベストな気がします。
https://angular.io/docs/ts/latest/
Tour of heroesという[チュートリアル](https://angular.io/docs/ts/latest/tutorial/)にそって一通り学べます。[Plunker](https://plnkr.co/)というブラウザ上でJSアプリが動作するWebサイトを使って各ステップごとのアプリが用意されているので、そこで簡単な動作確認をしつつ、ファイル一式をzipでダウンロードしローカルでいつものエディタでいじることも可能です。ダウンロードしたindex.htmlがあるディレクトリで[http-server](https://www.npmjs.com/package/http-server)などを立ち上げれば[system.js](https://github.com/systemjs/systemjs)というすごいやつがなんやかんやしてAngularが動くぞ！
ちなみにバンドラーとしてWebpack, Browserify, System.jsなどありますが、WebpackがAngular界隈では一番使われてる気がします。System.jsはAngularのすごい人がまだ早いって言ってた！(参照: [TechFeed Live#2レポート](https://html5experts.jp/shumpei-shiraishi/21731/))

チートシートも用意されているので、あれどうするんだっけ？とか、これなんだ？→調べる→学びが捗ります :thumbsup: 
https://angular.io/docs/ts/latest/guide/cheatsheet.html