内容は@oukayukaさんのりあクト! TypeScriptで始めるつらくないReact開発 第2版を参考にさせていただきました。
▼おことわり
あくまでもReact + TypeScriptのメリットだけをまとめ、文章やコードの転載などは極力避けたつもりです。
興味を持った方はぜひ買いましょう。ReactとTypeScriptに興味がある方なら絶対損しないと思います。
なお、内容に誤りがあったとしてもあくまで私の知識不足によってまとめ方を間違えているものであり、責任はあくまで私に帰属します。
これ転載じゃね?など規約違反・マナー違反に当たる内容があればご指摘いただければ幸いです。
▼補足
また、@yoichiwo7さんのReactとVueのどちらを選ぶかはReactのメリット・デメリットをVueとの比較で書かれており、とてもわかりやすい記事です。
ReactとVueで悩まれた方なら一度は読まれた記事ではないかと思いますが、Reactのメリットを手っ取り早く知りたい方におすすめです。
こちらも併せてどうぞ。
▼ざっくりReact + TypeScriptのメリット
- Reactによってリッチで複雑なUIを、細かい単位に分割しつつ、副作用を押さえながら開発できる
- TypeScriptによってより手軽に、軽量なアプリケーションを、エラーを減らしつつ作ることができる
▼React
●React誕生の背景
- スマホの普及により、Webでもネイティブアプリ並みにリッチなUIが求められるようになった
- MVCのような、コントローラーでの処理を待ってからビューの描画を行うという同期的な処理では上記のようなUIを実現することが難しかった
- そこでフロント側で非同期的にDOMの描画を変更するという必要性が生まれた
●Reactの基本思想
Reactの基本思想としては以下の3つが特に重要となる
- 仮想DOM
- コンポーネント指向
- 単方向データフロー
また、これらの思想を実現させるために関数型プログラミングのパラダイムを採用している
- 仮想DOM
- DOMと同じ構造のノードツリーを再現しておき、一連の処理結果の最終的な差分だけを元のDOMに書き戻すようにしたもの
- 生のDOMの更新はブラウザにとっては各種のオーバーヘッドが大きく、最適化するためには非常にコストがかかるためこのような方式が採用されている
- コンポーネント指向
- Web Componentの影響を受けている
- 再利用可能なカプセル化されたタグをJavaScriptを使って作り、これらを組み合わせることでアプリケーションを構築する
- 単方向データフロー
- データは必ず親コンポーネントから子コンポーネントへ一方通行で渡す
- AngularやVueはデータバインディングを採用しているため、この単方向データフローがReactを強く特徴付ける要因になっている
- 子コンポーネントの動きに応じて親コンポーネントを書き換える必要がある場合には、自身の状態を変更する関数を子コンポーネントに渡すなどの方法をとる
- 関数型や単方向データフローなどによって副作用を抑えた非同期処理を実現している
データバインディングを採用しなかった理由
- データバインディングはわかりやすい反面、コンポーネントの独立性は阻害している
- コンポーネント指向とは独立性の高いコンポーネントの組み合わせでアプリを構成する考え方であり、コンポーネントの中身がコンポーネントの知らないところで書き換わることを防ぎたかった
●Reactで関数型が採用されている理由
- 非同期にDOMの操作を行う以上、他の処理の結果に依存せず、参照透過性を担保することが望ましかったから
- つまり、処理が行われたタイミングや他のコンポーネントの状態によって処理の結果が変わってはならなかった
- これらの理由からReactはJSの処理の中にHTMLを埋め込むという、ロジックを優先したアプローチをとる
- ロジックを優先し、コンポーネント単位でロジックを完結させることを選んだため、同じ入力に対しては同じ結果を返すという関数型パラダイムになっているとも言える
- オブジェクト指向が非同期処理に不向きな理由
- クラスから生成されたオブジェクトは内部に状態を抱えていて、状態によって振る舞いが変わる
- 具体的にはメンバー関数の実行結果がメンバー変数に依存する
- クラスが状態と振る舞いをどちらも持っており、自分自身の状態を自分が変更するという処理が行われると参照透過性が担保できない
- つまり副作用が大きく、予測がしづらい
- フロントエンドの描画を非同期に行うということは、処理が行われたタイミングによって描画の結果が変わるというのは避けなければならない
- 関数型プログラミングとReactの特徴
- 関数型プログラミングとは、内部に状態を抱えずに、副作用を極力排したプログラミングを行うこと
- Reactは非同期なDOMの書き換えという難問を関数型プログラミングによって対処している
- 同じ入力に対して同じ作用と同じ出力が保証されていることを参照透過性という
- 状態を抱える必要がある場合には、状態を引数にとって新しい状態を返すようなやり方がよくとられる
- 状態も外部データとして扱い、振る舞いを分離させて副作用を抑えるやり方であるともいえる
▼TypeScript
●TypeScriptの人気度合い
- GitHubの2018年の月間アクティブユーザー数では10位(Rubyは11位)
- 成長率ランキングでは2位(1位はGo)
- Typescriptのシェアは2015年末ごろにはCoffeeScriptを上回った
- Nodeのカンファレンスで行われたアンケートでは、Babelを使って最新のECMAScriptをコンパイルするよりもTypescriptを使う人の方が多い
- React陣営も公式にTypescriptをサポートし始めた
●TypeScriptの人気の理由
- 言語特性が昨今のトレンドに合っていた
- エディタやIDEの進化により、言語特性を生かしやすかった
- サポートが手厚い、採用する企業が増えるなどの環境的な魅力が増大した
- (非同期処理やconst、letによる変数宣言などのECMAScriptの進化)
- 言語としての特性
- 静的型付け
- 型推論
- Null安全性
というトレンドを押さえつつ、文法のほとんどがJavaScriptと同じであることが人気の理由と推測される
上記トレンドを押さえている最近人気の言語
- Go
- Rust
- Kotlin(サーバーサイドKotlinの人気が特に高まりつつある?)
- Swift
静的型付け流行の理由
- 型の取り扱いの煩雑さを嫌って動的型付け言語が流行した
- 動的型付け言語も普及拡大に伴ってチームやプロダクトそのものが大規模化した
- 静的な型がないために、引数や返り値の型検証をテストで書いて保証する必要があった(TDDの文化発展の理由?)
- 型の保証やコンパイル時のチェックが行いやすいという点で静的型付け言語が再度流行した
型推論がもたらしたもの
- 型推論とは、型を書かなくとも処理系が文脈から型を予測して型付けしてくれる機能のこと
- 全てのケースで省略されるわけではないが、動的型付けの手軽さに近いものを実現できるようになった
Null安全性の利点
- Null安全な言語は、コンパイルの段階でNullになる可能性のあるコードをチェックしてくれる
- エディタやIDEの進化
- VSCodeなどのモダンなエディタやIDEはコンパイルをせずともコーディングの段階でNullチェックや推論された型の表示などを行ってくれる
- 周辺環境による魅力
- 開発元がMicrosoftである安心感
- 同じく開発元がMicrosoftであるVSCodeの普及とVSCodeによるTypeScriptサポートの手厚さ
- Googleが標準言語として採用している
●JavaScriptの進化
- ECMAScript2015(ES6)から、モダンな記法が取り入れられるようになった
- スコープがブロック単位の変数の宣言ができるようになった
- varの変数のスコープは関数単位であるため、制御構文のブロックをすり抜けてしまう
- 多くの言語では変数のスコープがブロック単位であるため、混乱が生じバグの温床となる
- constとletという、スコープがブロック単位の変数の宣言が盛り込まれた
- アロー関数が使えるようになった
- 関数の宣言が簡潔に書けるようになった
- デフォルト引数が使えるようになった
- ES2015からはデフォルト引数が使用可能になった
- クラス構文が使えるようになった
- ES6からはクラスが使用可能になった
- プロトタイプを用いる必要がなくなった
- 継承などももちろん行える
- 分割代入ができるようになった
以下、引用
const [n, m] = [1, 4]
console.log(n, m) // 1 4
const obj = { name: 'Kanae', age: 24 }; // オブジェクトを作成
const { name, age } = obj; // 分割代入
console.log(name, age) // Kanae 24
- スプレッド構文が使えるようになった
以下、引用
const arr1 = ['A', 'B', 'C'];
const arr2 = [...arr1, 'D', 'E']
console.log(arr2) // ['A', 'B', 'C', 'D', 'E']
const obj1 = { a: 1, b: 2, c: 3 };
const obj2 = { ...obj1, d: 4, e: 5 };
console.log(obj2) // { a: 1, b: 2, c: 3, d: 4, e: 5 }
- 配列のスプレッド構文はES6から
- オブジェクトのスプレッド構文はES2018から使えるようになった
- 非同期処理が扱いやすくなった
- JavaScriptでは時間のかかる処理はほぼ非同期であることが前提
- 通信やローカルファイルの読み込みなどの外部アクセスの処理など
- Promise構文やasync/await構文などの採用
▼まとめ
- WebアプリケーションのUIの複雑化に伴い、ビューの非同期な処理を予測・管理しつつ行うためには関数型が望ましかった
- 静的型付け言語やエディタ、IDEの進化により、動的型付け言語の優位性が薄れた
- Webアプリケーションの開発の大規模化によって、静的型付けを利用する動機が高まった
などの理由からReact + TypeScriptでのフロント開発にはメリットがあり、普及しているといえる。