Reactとの違い

PreactはReactの再実装ではありません。両者には違いがあります。ほとんどの違いは些細な物か、preact/compatによって吸収されます。preact/compatはReactとの100%の互換性を目指している薄いレイヤーです。

PreactがReactの機能をすべて含まない理由は小さい集中した状態を保ちたいからです。そうでないなら、単にReactプロジェクトを最適化する方が合理的です。Reactは既にとても複雑で素晴らしいアーキテクチャのコードベースで構成されています。



主な違い

PreactとReactの主な違いはPreactには合成イベント(Synthetic Event)がないことです。 Preactはイベント処理に内部でブラウザネイティブのaddEventListenerを使用しています。 DOMイベントハンドラの完全なリストはMDN's Event Referenceを見てください。

ブラウザのイベントシステムは必要なすべての機能を満たしているので、Preactにとって合成イベントは意味がありません。 合成イベントのようなカスタムイベントを完全に実装するとメンテナンスのオーバーヘッドが増加しAPIが複雑になってしまいます。

Reactの合成イベントとブラウザのネイティブイベントには以下のような違いがあります。

  • ブラウザイベントは<Portal>コンポーネントをイベントバブリングで通過しません。
  • IE11で<input type="search">要素の"x"クリアボタンはinputイベントを発火しません。代わりにonSearchを使います。
  • (preact/compatを使用していない場合は、)<input>要素ではonChangeの代わりにonInputを使用してください。

その他の主な違いはDOMの仕様にもう少しだけ似せていることです。 それの1つの例はclassNameの代わりにclassを使うことができることです。

バージョンの互換性

preactとpreact/compatの両方で、バーションの互換性はReactの現在と1つ前のメジャーリリースを比較します。 新機能がReactチームによって発表された場合、Projectの目的にとって意味がある場合はPreactコアへの追加が検討されます。 これはとても民主的なプロセスです。IssueやPull Requestでのオープンな議論や意思決定を通じて、Preactは継続的に進化しています。

従って、このウェブサイトとドキュメントのPreactとReactの互換性や比較はReact16.x15.xを対象にしています。

デバッグメッセージとエラー

Preactのアーキテクチャは柔軟性が高いので、アドオンを使用して自由自在にPreactの開発体験を向上させることができます。 preact/debugというアドオンを追加すると、有益な警告とエラーが表示されるようになり、 また、Preact Devtools がインストールされていれば、連携が有効化されます。 これらはPreactアプリケーションを開発する際のガイドになります。そして、何が起きているか調査することをとても簡単にします。 preact/debugアドオンは、次のimport文により追加できます。

import "preact/debug"; // <-- メインエントリーファイルの先頭にこの行を追加します。

Reactと異なるのは、(訳注:Preactではアドオンを使用してデバッグメッセージを追加するのに対して、)Reactでは、(訳注:最初からデバッグメッセージが含まれているので、プロダクション環境では、)NODE_ENV をチェックしてデバッグメッセージを削除するためにバンドラが必要、という点です。

Preact固有の機能

Preactは(P)Reactコミュニティの活動から生まれたアイディアをベースに便利な機能を追加しています。

ES Modulesをネイティブサポート

Preactは、当初からES Modulesを考慮して開発されており、ES Modulesをサポートする最初のフレームワークの1つになりました。 前もってバンドラに通すことなしに、ブラウザでimportキーワードを使ってPreactを直接ロードすることができます。

`Component.render()`の引数

Preactでは、利便性のために、クラスコンポーネントのthis.propsthis.staterender()に引数として渡します。 1つのpropsと1つのstateを使用する以下のコンポーネントを見てください。

// PreactとReactの両方で動作します。
class Foo extends Component {
  state = { age: 1 };

  render() {
    return <div>Name: {this.props.name}, Age: {this.state.age}</div>;
  }
}

Preactではこれを以下のように書くことができます。

// Preactのみ動作します。
class Foo extends Component {
  state = { age: 1 };

  render({ name }, { age }) {
    return <div>Name: {name}, Age: {age}</div>;
  }
}

両方とも全く同じ物をレンダリングします。どちらのスタイルを選ぶかは単なる好みの問題です。

そのままのHTML属性/プロパティ名

Preactは、すべての主要なブラウザでサポートされているDOMの仕様にReactより忠実です。 Reactとの主な違いの1つはclassName属性の代わりに標準のclass属性を使うことができることです。

<div class="foo" />

// 上記は下記と同じ
<div className="foo" />

両方ともサポートされていますが、ほとんどのPreact開発者は短く書くことができるのでclassを使うことを好みます。

`onChange`の代わりに`onInput`を使う

主に歴史的な事情によって、ReactのonChangeイベントは、ブラウザによって提供されているonInputイベント(これは全てのブラウザで動作します)と同じ動作をします。 一方で、Preactでは、onChangeはユーザによって要素の値の変更が確定されたときに発生する標準のDOMイベントです。 フォームコントロールが変更された時に何かを行いたい場合、onInputイベントが適していることが多いです。

// React
<input onChange={e => console.log(e.currentTarget.value)} />

// Preact
<input onInput={e => console.log(e.currentTarget.value)} />

preact/compatでは、Reactの挙動を再現するために、onChangeonInputと同じ動作になるよう内部で変換されます。 これにより、Reactエコシステムとの最大限の互換性を確保しています。

JSXコンストラクタ

このアイディアは元はhyperscriptと呼ばれていました。これはReactのエコシステムに限らず価値があります。 だから、Preactは元のやり方を推奨しています。(詳しくは: why `h()`?) h()はトランスパイルされたコードを見るとReact.createElementより少し読みやすいです。

h(
  'a',
  { href:'/' },
  h('span', null, 'Home')
);

// vs
React.createElement(
  'a',
  { href:'/' },
  React.createElement('span', null, 'Home')
);

ほとんどのPreactアプリケーションではh()が使用されています。 しかし、コアではh()createElement()の両方がサポートされています。 どちらを使うかは重要ではありません。

contextTypesは必要ありません

Reactの古いコンテキストAPIではコンポーネントにcontextTypesもしくはchildContextTypesを実装する必要があります。 Preactではこの制限はありません。すべてのコンポーネントはgetChildContext()から生成されたすべてのcontextの値を受け取ります。

`preact`には無くて`preact/compat`にある機能

preact/compatはReactのコードをPreactに移行するための互換レイヤーです。 既存のReactユーザはコードはそのままでバンドラの設定にいくつかのエイリアスをセットするだけで、とても手軽にPreactを試すことができます。

Children API

ReactのChildrenAPIはコンポーネントのchildrenを反復処理するためのAPIです。 PreactではこのAPIは必要ありません。代わりにネイティブの配列のメソッドを使うことを推奨します。

// React
function App(props) {
  return <div>{Children.count(props.children)}</div>
}

// Preact: 子コンポーネントを配列に変換します。配列の標準のプロパティを使います。
function App(props) {
  return <div>{toChildArray(props.children).length}</div>
}

固有のコンポーネントと関数

preact/compatは以下のような特殊な用途で使用することを目的としたコンポーネントや関数を提供しています。

  • PureComponent: propsもしくはstateが変化した場合のみ更新されます。
  • memo: PureComponentと用途が似ていますがこちらは比較のための関数を指定することができます。
  • forwardRef: 指定した子コンポーネントにrefをセットします。
  • Portals: 指定した仮想DOMツリーを別のDOMコンテナにレンダリングします。
  • Suspense: 実験的機能 仮想DOMツリーの準備ができていない間は代替の仮想DOMツリーのレンダリングすることを可能にします。
  • lazy: 実験的機能 非同期のコードを遅延ロードします。そして、ロード完了を通知します。

Built by a bunch of lovely people ubitools.com