Transcript
00:00:00最初はJSXがあり、次にTSXが登場しましたが、私たちは何年もこれらに縛られてきました。
00:00:04これらを改善することはできないのでしょうか? もしかしたら、TSRXなら可能かもしれません。
00:00:08似ているようで、どこか違います。
00:00:10関数(function)の代わりに「component」を使い、テキストには文字列を使用し、
00:00:14中には普通の if 文があり、さらに return 文もありません。
00:00:17これは一体何なのか、なぜ存在するのか、そして使うべきなのか? 探っていきましょう。
00:00:21[音楽]
00:00:26さて、実際にこのようなコードを見たことがある方も、一部いらっしゃるかもしれません。
00:00:29というのも、これは実は「Ripple」の制作者によって提供されているからです。
00:00:31これは新しいフロントエンドフレームワークで、半年前にRichがこのチャンネルで紹介しました。
00:00:35最新情報を逃さないために、ぜひチャンネル登録をお願いします。
00:00:38彼らがやったのは、Rippleで使用されていた構文を抽出し、
00:00:41React、Preact、Solid、Vue、そしてもちろんRippleでも動作するようにしたことです。
00:00:45これには多くの人々がかなり期待を寄せていました。
00:00:47TSRXは、UIコンポーネントの可読性とコロケーション(近接配置)を維持するための方法だと説明されています。
00:00:52つまり、構造、スタイリング、制御フローが共存し、
00:00:55その結果、TypeScriptとの完全な後方互換性が維持されます。
00:00:58しかし、Rippleを使ったことがなければ、それがどういう意味かまだ少し混乱しているでしょう。
00:01:01そこで、その特徴を順番に見ていきましょう。
00:01:03まず、これは .tsrx ファイルで使用するため、コンパイルの手順が必要になりますが、
00:01:07Viteプラグインを使えば、設定は非常に簡単です。
00:01:10また、他のフレームワークやランタイム向けのオプションも用意されています。
00:01:13実際のコンポーネントについては、ここで「function」と書く代わりに「component」と書きます。
00:01:17これは主にコンパイラ自体に対するキーワードに過ぎませんが、
00:01:20ここにレンダリングロジックが含まれることを明確にする役割もあります。
00:01:24ちょっとしたQOL(使いやすさ)の向上と言えるかもしれません。
00:01:27ただし、ここで注目すべきは、return 文がないことです。
00:01:30これは、TSRXが「ステートメント(文)ベースのJSX」を使用しているためです。
00:01:33そのため、コンポーネントツリーを返す必要はなく、
00:01:35レンダリングしたい場所にマークアップをそのまま書くだけです。
00:01:37つまり、コンポーネントの最上部にあるこのカードの上に、別の p タグをそのまま挿入でき、
00:01:42書かれた場所にそのままレンダリングされます。
00:01:44コンポーネント内で return を使用することもできますが、それは値を持たない素の return である必要があり、
00:01:47早期リターンのためにのみ使用されます。これにより、それ以降のUIとロジックはスキップされます。
00:01:51TSRXのコンポーネントは非常に直線的(リニア)であると考えると分かりやすいでしょう。
00:01:54ソースコードを書いた順序が、そのままレンダリングの順序になります。
00:01:57単純に上から下へと読み進める形です。
00:01:59しかし同時に、コンポーネントが何をレンダリングしているのかを素早く見極めるのが
00:02:03難しくなるかもしれないとも思います。Reactなどでは、すぐに return 文へと目を向けますからね。
00:02:06ステートメントベースのJSXのもう一つの利点は、より普通のJavaScriptを多く使用できることです。
00:02:10例えば、条件付きレンダリングは非常にシンプルです。
00:02:13必要に応じて else-if や else を伴う、ただの if 文です。
00:02:17条件の中では、JSXをステートメントとして配置するだけです。
00:02:20Reactでこれと同じ形にしようとすると、三項演算子のネストになりがちです。
00:02:23JSXではすべての分岐が「式(expression)」でなければならないからです。
00:02:26そのため、TSRXバージョンの法が読みやすく感じられることがあります。
00:02:29特に、より複雑な条件文を扱う場合にはそうです。
00:02:31しかし同様に、これが冗長さを増す原因になることも理解できます。
00:02:35特に、単純な条件だけで済ませたい場合にはそう感じられるでしょう。
00:02:37switch 文についても同様です。
00:02:39通常のJavaScriptの switch をそのまま使い、各ケースと
00:02:41それぞれでレンダリングしたいJSXを記述できます。
00:02:44これはReactでの処理方法よりも少しシンプルです。
00:02:47Reactで同じパターンを使うには、関数を挟む必要があります。
00:02:49そのため、この点においてはTSRXの方が少しスマートです。
00:02:51しかし、個人的にTSRXであまり好みではないのが、リストのレンダリングです。
00:02:55ここでは .map を捨てて、代わりに for-of ループを使用します。
00:02:58さらにTSRXはこのループを拡張しており、インデックスを取得できるほか、
00:03:01keyによる安定した識別も可能です。
00:03:03そして、特定の要素をスキップしたいときは、単に continue を使用できます。
00:03:06これもまた、バニラJavaScriptのフローに近い形になっています。
00:03:08ただ先ほど言ったように、私は .map や .filter を使うことにすっかり慣れてしまっているので、
00:03:12おそらく今後もそれらを使い続けるでしょう。
00:03:14また、他のループ形式(for、for-in、while、do-whileなど)は
00:03:17使用できない点にも注意が必要です。
00:03:19これが機能するのは for-of ループのみです。
00:03:21さて、普通のJavaScriptを使うというトレンドを引き継ぎ、
00:03:23TSRXでのエラーバウンダリは、シンプルな try-catch ブロックで行います。
00:03:27特別なことは何もなく、非常に分かりやすいものです。
00:03:30非同期バウンダリ(Suspense相当)が必要な場合も、同じ try-catch ブロックを使用できます。
00:03:33単に pending ブロックを追加し、
00:03:35その中にローディングコンポーネントを記述するだけです。
00:03:38コンパイラが実際にこのコードを処理し、
00:03:40使用しているフレームワークに応じたコードへと解決してくれます。
00:03:42React、Preact、Solidでは、これは実際には lazy を使用し、
00:03:45Rippleでは、Rippleにおける同等の機能が使われます。
00:03:47特にReactについて話すと、
00:03:48ここまで見てきた機能は、
00:03:50Reactの重要なルールの一つを破ることを可能にしているように見えます。
00:03:53そう、「Hooksのルール」です。
00:03:54フックを条件分岐や早期リターンの後に配置したり、
00:03:57ループの内部に配置することさえ可能になります。
00:03:58これらはすべて通常通りに動作します。
00:04:00これにより、コードを実際に必要な場所により良く共存させることができ、
00:04:03しかも最終的な出力コードはルールを破っていません。
00:04:06コンパイラが、生成された関数の最上部にすべてのフックを静かにホイスティング(巻き上げ)するため、
00:04:09React側からは常に安定した順序でそれらが見えることになります。
00:04:11しかし、開発者はそれらを本来あるべき場所に記述できるのです。
00:04:14Reactを何年も使ってきた私個人としては、
00:04:16これは慣れるのに最も苦労する部分の一つです。
00:04:18また、この機能はコンパイラに
00:04:20舞台裏で多くの「魔法」を実行させています。
00:04:22特に特定のフレームワークの仕様に合わせてです。
00:04:24そのため、もしデバッグをすることになったら、
00:04:26どのコードがどこにあるのか少し迷ってしまうかもしれません。
00:04:28次はレキシカルスコープ(静的スコープ)についてです。
00:04:30ネストされたすべての要素が独自のスコープを作成します。
00:04:32そのため、ここでは3つの異なる div ブロック内で const label を宣言していますが、
00:04:36それらが衝突することはありません。
00:04:37関数の最上部にも1つ宣言されていますが、何もそれを読み取っておらず、
00:04:40これも競合していません。
00:04:41同様のことが、すべての if、for、switch、try ステートメントにも当てはまります。
00:04:44それぞれが独自のスコープを持っています。
00:04:46そのため、宣言する変数、実行する関数、
00:04:48そして算出する値が、他のスコープに漏れ出すことはありません。
00:04:51これもまた、コードを身近にまとめることに焦点を当てた機能であり、
00:04:54やはりコンポーネントを上から下へと直線的に読めるようにしてくれます。
00:04:57JavaScriptから視点を変えて、今度はスタイリングについて話しましょう。
00:05:00TSRXには、スコープされたスタイル(CSS)があります。
00:05:02コンポーネント内に style ブロックを配置するだけで、
00:05:04そこに書いたCSSはそのコンポーネント内のみにスコープされます。
00:05:08コンパイル時に、クラス名に一意のハッシュ値が添付される仕組みです。
00:05:11この card コンポーネントには card クラスがあります。
00:05:13ここで注目してほしいのは、こちらでも同じ card クラスを使おうとしていますが、
00:05:16card スタイルは一切適用されません。
00:05:17なぜなら、これ自体には style ブロックがないからです。
00:05:19親要素からスタイルが引き継がれることもありません。
00:05:21一意のハッシュ値を持っていないからです。
00:05:22もしコンポーネント間でスタイルを共有したい場合は、
00:05:24TSRXに用意されている style キーワードを使用します。
00:05:26親コンポーネントはこのキーワードを使ってスタイル名を渡し、
00:05:29className をプロップとして受け取るコンポーネントに伝達します。
00:05:31これにより、生成された一意のハッシュ値が確実に一緒に渡されるようになります。
00:05:35これで、親と同じスタイルが適用されているのが分かります。
00:05:37技術的には、スタイルの周りにグローバルセレクタを使用して
00:05:40スコープを抜け出し、それらのスタイルをグローバルに適用することもできますが、
00:05:42少し煩雑になり、
00:05:44スタイルがどこから来ているのか分からなくなると思います。
00:05:46個人的に、私は完全にTailwind派なので、
00:05:48おそらくこの機能はあまり使わず、
00:05:50Tailwindを使い続けるでしょう。
00:05:51それでも、非常にクールな機能であることには変わりありません。
00:05:53次は、鋭い観察力をお持ちの方のための機能です。
00:05:56これまでお見せしたコードブロックにおいて、
00:05:57これらのステートメント内のテキストの扱いに、小さな違いがあったことにお気づきでしょうか。
00:06:01要素内の生のテキストは、ダブルクォーテーションで囲む必要があります。
00:06:04JSXのように、ただそのまま書くことはできません。
00:06:07動的な値を使用することは依然として可能ですが、
00:06:08例えばこのような行では、
00:06:102つのダブルクォーテーションで囲まれた文字列の間に挟む形になり、
00:06:12TSRXはコンパイル時にこれらを単一の文字列に連結します。
00:06:16もう一つの選択肢として、単にテンプレートリテラルを使い続けることもできます。
00:06:19同じ結果が得られます。
00:06:20私にとって、これはTSRXを使う上での小さな不満点(ペーパーカット)の一つでした。
00:06:23テキストにクォーテーションを使わないというマッスルメモリー(身体感覚)が染み付いているからです。
00:06:26しかし、テキスト関連のもう一つの機能として、
00:06:27TSRXは実際のHTMLマークアップを含む文字列を扱うことができます。
00:06:31そして、これをレンダリングする方法は2つあります。
00:06:331つ目は、単に text キーワードを使用する方法です。
00:06:35これにより、エスケープされたテキストがレンダリングされます。
00:06:38そのため、生のHTML文字列がそのまま表示され、
00:06:40クロスサイトスクリプティングに対しても安全です。
00:06:42これは、あるデータが確実に文字列であることを保証したいときに便利です。
00:06:45その文字列のソースが少し曖昧で、
00:06:48コードを書いている時点ではその型が分からない場合などに役立ちます。
00:06:512つ目の選択肢は、文字列をHTMLとしてレンダリングしたい場合です。
00:06:54シンプルに html キーワードを使用します。
00:06:56これにより、本物のHTMLとして解析されます。
00:06:58ただし、この機能はRippleでのみ動作し、Vueではその狭いサブセットのみがサポートされています。
00:07:02Reactには関係ありませんが、
00:07:03Ripple、Vue、Solidを使っている方にとって興味深いかもしれない機能が、
00:07:06「レイジー・デストラクチャリング(遅延分割代入)」です。
00:07:08これらのフレームワークで通常通り props を分割代入すると、
00:07:10呼び出し時にそれぞれの値のスナップショットが作成され、
00:07:12アクセスごとのリアクティビティが損なわれてしまいます。
00:07:14そこでTSRXでは、propsの前にアンパサンド(&)を付けるだけで、
00:07:18分割代入のように見えながら、
00:07:20それぞれのバインディングが実際に使用される場所で、プロパティのルックアップへとコンパイルされます。
00:07:23そのため、ランタイムは各アクセスを個別に認識し、
00:07:25シグナルの更新によって再レンダリングが正しくトリガーされます。
00:07:28つまり、分割代入の書きやすさを維持したまま、
00:07:30フレームワーク側のリアクティビティも維持できるということです。
00:07:32最後にお見せする機能は、非常にシンプルで素晴らしいQOL向上機能です。
00:07:35プロップに渡す値が、そのプロップと同じ名前を持っている、ということはありませんか?
00:07:40最も一般的なのは onChange 関数のような場合です。
00:07:42TSRXでは、これを省略形(ショートハンド)で書くことができます。
00:07:45JavaScriptのオブジェクトにおける記述方法と似ています。
00:07:47スマートでシンプルですね。
00:07:49全体として、TSRXは通常のJavaScriptのフローをJSXに融合させ、
00:07:53さらにいくつかのQOL向上要素を加えようとしているように感じられます。
00:07:55私はその要素の多くをとても気に入っています。
00:07:57ただ、私にとっての最大のネックは、これがニッチすぎて、かつ登場が遅すぎた点です。
00:08:01今やAIが私たちのコードの大部分を書く時代であり、
00:08:03AIが最も得意とするコードはJSXとReactだからです。
00:08:07そうは言いつつも、TSRXを使ったデモをいくつかClaudeに入力してみたところ、
00:08:10サイトの LLM.txt に基づいて、非常にうまくコードを書いてくれました。
00:08:14それでも、私は今後も通常のReactを使い続けると思います。
00:08:17もう一つの欠点は、特にReactにおいて、
00:08:19コンパイラの魔法がさらにその上に重ねられているように感じられる点です。
00:08:21また、私が何年もかけて学んできたフローを崩すものでもあります。
00:08:24そのため、個人的には使いませんが、それが悪いという意味ではありません。
00:08:27Svelteから移行する人にとっては、非常に好まれるかもしれませんし、
00:08:30すでにRippleを使っている人なら、間違いなく気に入るでしょう。
00:08:33もし気に入ったら、下のコメント欄で教えてください。
00:08:35チャンネル登録も忘れずに。それではまた次回の動画でお会いしましょう。
00:08:40[音楽]
Community Posts
No posts yet. Be the first to write about this video!
Write about this video