Reactとの違い
PreactはReactの再実装を意図したものではありません。いくつか違いがあります。これらの違いの多くは些細なもので、preact/compatを使用することで完全に取り除くことができます。これはPreactの上に薄く重ねられたレイヤーであり、Reactとの100%の互換性を実現しようとします。
PreactがReactのすべての機能を実装しようとしない理由は、小さく、焦点を絞った状態を維持するためです。そうでない場合は、Reactプロジェクトに最適化を送信する方が理にかなっています。Reactプロジェクトはすでに非常に複雑で、十分に設計されたコードベースです。
主な違い
PreactとReactの主な違いは、Preactがサイズとパフォーマンス上の理由から合成イベントシステムを実装していないことです。Preactは、ブラウザの標準addEventListener
を使用してイベントハンドラーを登録します。これは、イベントの命名と動作が、プレーンなJavaScript / DOMでの場合と同じようにPreactで動作することを意味します。DOMイベントハンドラーの完全なリストについては、MDNのイベントリファレンスを参照してください。
標準のブラウザイベントは、Reactのイベントと非常に似たように動作しますが、いくつかの小さな違いがあります。Preactでは
- イベントは
<Portal>
コンポーネントを介してバブリングしません - フォーム入力には、Reactの
onChange
の代わりに標準のonInput
を使用する必要があります(preact/compat
を使用していない場合のみ) - Reactの
onDoubleClick
の代わりに標準のonDblClick
を使用する必要があります(preact/compat
を使用していない場合のみ) - IE11ではクリア「x」ボタンが
onInput
を発火しないため、<input type="search">
には一般的にonSearch
を使用する必要があります
もう1つの注目すべき違いは、PreactがDOM仕様により密接に従っていることです。カスタム要素は他の要素と同様にサポートされており、カスタムイベントは(DOMの場合と同様に)大文字と小文字を区別する名前でサポートされています。
バージョン互換性
preactとpreact/compatの両方について、バージョン互換性はReactの現在および以前のメジャーリリースに対して測定されます。Reactチームによって新しい機能が発表されると、プロジェクトの目標を考慮して、それが理にかなっていればPreactのコアに追加される場合があります。これは、オープンな議論や、イシューとプルリクエストを使用して行われた決定を通じて常に進化している、かなり民主的なプロセスです。
したがって、Webサイトとドキュメントでは、互換性について説明したり、比較を行ったりするときに、React
15.x
から17.x
を反映しています。
デバッグメッセージとエラー
柔軟なアーキテクチャにより、アドオンはPreactのエクスペリエンスを好きなように拡張できます。それらのアドオンの1つは、役立つ警告とエラーを追加し、インストールされている場合はPreact開発者ツールブラウザ拡張機能をアタッチするpreact/debug
です。これらは、Preactアプリケーションを開発する際にガイドとなり、何が起こっているかを検査するのがはるかに簡単になります。関連するインポートステートメントを追加することで、それらを有効にできます
import "preact/debug"; // <-- Add this line at the top of your main entry file
これは、NODE_ENV != "production"
をチェックすることで、ビルド時にデバッグメッセージを削除するバンドラーが存在する必要があるReactとは異なります。
Preact独自の機能
Preactは実際には、(P)Reactコミュニティでの作業に触発されたいくつかの便利な機能を追加します
ESモジュールのネイティブサポート
Preactは最初からESモジュールを念頭に置いて構築されており、それらをサポートした最初のフレームワークの1つでした。バンドラーを最初に通過させることなく、ブラウザでimport
キーワードを介してPreactを直接ロードできます。
Component.render()
の引数
便宜上、クラスコンポーネントのrender()
メソッドにthis.props
とthis.state
を渡します。1つのpropと1つのstateプロパティを使用するこのコンポーネントを見てください。
// Works in both Preact and React
class Foo extends Component {
state = { age: 1 };
render() {
return <div>Name: {this.props.name}, Age: {this.state.age}</div>;
}
}
Preactでは、これもこのように記述できます
// Only works in Preact
class Foo extends Component {
state = { age: 1 };
render({ name }, { age }) {
return <div>Name: {name}, Age: {age}</div>;
}
}
どちらのスニペットもまったく同じものをレンダリングします。レンダリング引数は便宜上提供されています。
生のHTML属性/プロパティ名
Preactは、すべての主要なブラウザでサポートされているDOM仕様に厳密に一致することを目指しています。要素にprops
を適用するとき、Preactは各propをプロパティとして設定するかHTML属性として設定するかを検出します。これにより、カスタム要素に複雑なプロパティを設定できますが、JSXでclass
のような属性名を使用することもできます。
// This:
<div class="foo" />
// ...is the same as:
<div className="foo" />
ほとんどのPreact開発者は、記述が短いclass
を使用することを好みますが、どちらもサポートされています。
JSX内のSVG
SVGは、そのプロパティと属性の名前に関して非常に興味深いものです。SVGオブジェクトの一部のプロパティ(およびその属性)はキャメルケース(例:clipPath要素のclipPathUnits)で、一部の属性はケバブケース(例:多くのSVG要素のclip-path)、およびその他の属性(通常はDOMから継承されたもの、例:oninput
)はすべて小文字です。
Preactは、SVG属性を記述されたとおりに適用します。つまり、変更されていないSVGスニペットをコードにコピーして貼り付けると、すぐに動作します。これにより、デザイナーがアイコンやSVGイラストを生成するために使用するツールとの相互運用性が向上します。
// React
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<circle fill="none" strokeWidth="2" strokeLinejoin="round" cx="24" cy="24" r="20" />
</svg>
// Preact (note stroke-width and stroke-linejoin)
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48">
<circle fill="none" stroke-width="2" stroke-linejoin="round" cx="24" cy="24" r="20" />
</svg>
Reactから移行する場合は、すべての属性をキャメルケースで指定することに慣れているかもしれません。preact/compatをプロジェクトに追加することで、常にキャメルケースのSVG属性名を使用し続けることができます。これはReact APIをミラーリングし、これらの属性を正規化します。
onChange
の代わりにonInput
を使用する
主に歴史的な理由から、ReactのonChange
イベントのセマンティクスは、ブラウザによって提供されるonInput
イベントと同じであり、これはどこでもサポートされています。input
イベントは、フォームコントロールが変更されたときに反応したい場合に最適です。Preactコアでは、onChange
は、要素の値がユーザーによってコミットされたときに発生する標準のDOM changeイベントです。
// React
<input onChange={e => console.log(e.currentTarget.value)} />
// Preact
<input onInput={e => console.log(e.currentTarget.value)} />
preact/compatを使用している場合、ほとんどのonChange
イベントは、Reactの動作をエミュレートするために内部的にonInput
に変換されます。これは、Reactエコシステムとの最大の互換性を確保するために使用するトリックの1つです。
JSXコンストラクタ
JSXはJavaScriptの構文拡張であり、ネストされた関数呼び出しに変換されます。これらのネストされた呼び出しを使用してツリー構造を構築するという考え方は、JSXよりもずっと前から存在し、以前はJavaScriptでhyperscriptプロジェクトによって普及しました。このアプローチはReactエコシステムの範囲をはるかに超えて価値があるため、Preactはオリジナルの汎用化されたコミュニティ標準を推進しています。JSXとそのHyperscriptとの関係についてのより詳細な議論については、JSXの仕組みに関するこの記事をお読みください。
ソース: (JSX)
<a href="/">
<span>Home</span>
</a>
出力
// Preact:
h(
'a',
{ href:'/' },
h('span', null, 'Home')
);
// React:
React.createElement(
'a',
{ href:'/' },
React.createElement('span', null, 'Home')
);
最終的に、Preactアプリケーションの生成された出力コードを見ると、短くて名前空間のない「JSXプラグマ」の方が読みやすく、ミニファイなどの最適化に適していることは明らかです。ほとんどのPreactアプリではh()
が見られますが、createElement
エイリアスエクスポートも提供されているため、実際にはどの名前を使用しても問題ありません。
contextTypesは不要
従来のContext
APIでは、値を受け取るために、コンポーネントはReactのcontextTypes
またはchildContextTypes
を使用して特定のプロパティを宣言する必要があります。Preactにはこの要件はありません。すべてのコンポーネントは、デフォルトでgetChildContext()
によって生成されたすべてのcontext
プロパティを受け取ります。
preact/compat
に固有の機能
preact/compat
は、ReactコードをPreactに変換する互換性レイヤーです。既存のReactユーザーにとって、これは、バンドラー構成でいくつかのエイリアスを設定することで、コードを変更せずにPreactを試す簡単な方法になります。
Children API
Children
APIは、props.children
の値の操作に特化したメソッドのセットです。Preactでは、これは一般的に不要であり、代わりに組み込みの配列メソッドを使用することをお勧めします。Preactでは、props.children
は仮想DOMノード、null
のような空の値、または仮想DOMノードの配列のいずれかです。最初の2つのケースは最も単純で一般的です。children
をそのまま使用または返すことができるためです。
// React:
function App(props) {
return <Modal content={Children.only(props.children)} />
}
// Preact: use props.children directly:
function App(props) {
return <Modal content={props.children} />
}
コンポーネントに渡された子を反復処理する必要がある特殊なケースでは、Preactは任意のprops.children
値を受け取り、フラット化および正規化された仮想DOMノードの配列を返すtoChildArray()
メソッドを提供します。
// React
function App(props) {
const cols = Children.count(props.children);
return <div data-columns={cols}>{props.children}</div>
}
// Preact
function App(props) {
const cols = toChildArray(props.children).length;
return <div data-columns={cols}>{props.children}</div>
}
React互換のChildren
APIは、既存のコンポーネントライブラリとの統合をシームレスにするために、preact/compat
から入手できます。
特殊なコンポーネント
preact/compatには、すべてのアプリで必要なわけではない特殊なコンポーネントが付属しています。これらには以下が含まれます。
- PureComponent:
props
またはstate
が変更された場合にのみ更新 - memo:
PureComponent
と同様の概念ですが、カスタムの比較関数を使用できます - forwardRef: 指定された子コンポーネントに
ref
を提供します。 - Portals: 現在のツリーのレンダリングを別のDOMコンテナで継続します
- Suspense: 実験的 ツリーの準備ができていない場合にフォールバックコンテンツを表示できます
- lazy: 実験的 非同期コードを遅延読み込みし、ツリーを準備完了/未準備としてマークします。