https://qiita.com/uhyo/items/ff243a5771077aaf4b5b?utm_campaign=post_article&utm_medium=twitter&utm_source=twitter_share

前回のおさらい

前回の記事では、Reactに有利なベンチマークでUIライブラリに競ってもらいました。

こういうベンチマークに対しては、「実務では〜」みたいな反応が一定数出てくるのが自然の摂理です。

書きやすさランキング

そこで、シリーズのまとめとして、より実務に近い指標として「書きやすさ」で競ってもらおうと思います。ただし、今回は筆者の独断と偏見によるランキングとなります。せっかく6つのライブラリで同じアプリケーションを書いたので、感想を記事にして残しておきたいという意図です。筆者と同じくReact脳の方にとっては参考になるかもしれません。

なお、前の記事を読んだ方はお分かりの通り、今回書いたアプリケーションはコンポーネントが何個かのものであり、React以外の知識は公式ドキュメントを一通り読んだ程度です。したがって、今回のランキングはコンポーネントの書きやすさに着目しています。大規模開発のノウハウなどは考慮されていないのでそこはご理解ください。

ではさっそくランキングを見ていきましょう。

1位: React

React脳なので当然1位はReactです。なお、Preactもアーキテクチャが同じなので同率1位です。

Reactのアーキテクチャはこのランキングに登場するライブラリの中でも特殊で、コンポーネントはpropsやstateからUI (ブラウザの場合はDOM) を出力する純粋関数であるというのが基本です。他のライブラリはコンポーネントを表すスクリプトが初期化時の1回しか実行されなかったりしますが、Reactの関数コンポーネントはレンダリングのたびに実行されます。

それゆえに、(JSXをJavaScriptの一部として認めれば)「ただのJavaScript」でコンポーネントが出力するUIを定義できるのがReactの大きな魅力です。これは、他のライブラリでv-ifなどのディレクティブを使わないといけないのと対照的で、筆者がReactを特に好む理由のひとつです。Early returnを使うなどJavaScriptのテクニックも自由に使うことができ、UIを出力するロジックを書くという点においてもっとも長けていると思います。

early returnを使ってUIを書く様子

  if (!item) {
    return null;
  }

  return (
    <div className={classes.wrapper}>
      <div className={classes.id}>{item.id}</div>
      <div>{nameMarked}</div>
      <div>{item.ja}</div>
    </div>
  );

ただ、ReactではuseEffectに代表されるフックのAPIを用いてコンポーネントに副作用などのロジックを添加できるのが特徴的です。フックのルールによりearly returnしたあとにフックを使ってはいけないなどの制約があり、これはやや不便と言わざるを得ません(筆者もたまに間違えます)。

  if (!item) {
    return null;
  }

  // ここでフックを使うのはだめ
  const { prefix, marked, suffix } = useMemo(() => {
    // ...
  }, [item]);

  return (
    <div className={classes.wrapper}>
      <div className={classes.id}>{item.id}</div>
      <div>...</div>
      <div>{item.ja}</div>
    </div>
  );

この制約により、フックを使うパートを関数コンポーネント内の先にまとめて、UIの出力を最後で行うのが常套手段となります。もっとも、Reactではフックの中(useMemoなど)でもJSXを組み立てられるのでこの制約はあまり苦になることがありません。

関数コンポーネント時代におけるReactの特徴は、コンポーネントの実体(インスタンス)が我々から見えないところで管理されているということです。クラスコンポーネントの場合はクラスのインスタンスがコンポーネントの実体として、そのコンポーネントのライフサイクルの間生存しており、我々はthisなどを通じてそれに触れることができました。一方、関数コンポーネントの場合はその実体に直接触れることはできず、useStateuseRefなどのフックを用いることで、その実体が持つ記憶領域に断片的なアクセスをすることができます。これが、関数コンポーネントがレンダリングされるたびに呼び出されるにもかかわらずコンポーネントがステートなどを持つことができるからくりです。

このように、フックはコンポーネントの実体とコンポーネントのコードの間に抽象化レイヤーを挟むためのAPIだと見ることができます。その利点はより高い凝集度のロジックを書けることです。