Preact 8.x からのアップグレード
このドキュメントは、既存の Preact 8.x アプリケーションを Preact X にアップグレードする手順を説明することを目的としており、主に 3 つのセクションに分かれています。
Preact X には、Fragments
、hooks
、React エコシステムとの互換性の大幅な向上など、多くのエキサイティングな新機能が搭載されています。破壊的変更は可能な限り最小限に抑えるように努めましたが、機能セットを犠牲にすることなくすべてを完全に排除することはできませんでした。
依存関係のアップグレード
注: このガイド全体を通して、npm
クライアントを使用します。コマンドは、yarn
などの他のパッケージマネージャーにも簡単に適用できます。
それでは始めましょう!最初に Preact X をインストールします
npm install preact
compat がコアに移動したため、preact-compat
はもう必要ありません。これで削除します
npm remove preact-compat
Preact 関連ライブラリの更新
ユーザー(特にエンタープライズユーザー)に安定したエコシステムを保証するために、Preact X 関連ライブラリのメジャーバージョンアップデートをリリースしました。preact-render-to-string
を使用している場合は、X で動作するバージョンにアップデートする必要があります。
ライブラリ | Preact 8.x | Preact X |
---|---|---|
preact-render-to-string | 4.x | 5.x |
preact-router | 2.x | 3.x |
preact-jsx-chai | 2.x | 3.x |
preact-markup | 1.x | 2.x |
Compat がコアに移動
サードパーティの React ライブラリを Preact で動作させるために、preact/compat
を介してインポートできる**compat**ibility レイヤーを提供しています。以前は別パッケージとして提供されていましたが、調整を簡単にするためにコアリポジトリに移動しました。そのため、既存のインポートまたはエイリアス宣言を preact-compat
から preact/compat
に変更する必要があります(スラッシュに注意)。
スペルミスを導入しないように注意してください。一般的なミスとして、compat
の代わりに compact
と書くようです。それが難しい場合は、compat
を react の `compatibility` レイヤーとして考えてください。そこから名前が来ています。
preact-cli
を使用している場合は、このステップはすでに完了しています :tada
サードパーティライブラリ
破壊的変更の性質上、既存のライブラリの一部は X では動作しなくなる可能性があります。それらのほとんどは、ベータスケジュールに従ってすでに更新されていますが、そうでないものに遭遇する可能性があります。
preact-redux
preact-redux
は、まだ更新されていないそのようなライブラリの 1 つです。良いニュースは、preact/compat
が React に大幅に準拠しており、react-redux
という React バインディングでそのまま動作することです。それに切り替えることで状況は解決します。バンドラーで react
と react-dom
を preact/compat
にエイリアスしていることを確認してください。
preact-redux
を削除しますreact-redux
をインストールします
mobx-preact
react エコシステムとの互換性が向上したため、このパッケージは不要になりました。代わりに mobx-react
を使用してください。
mobx-preact
を削除しますmobx-react
をインストールします
styled-components
Preact 8.x は styled-components@3.x
までしか動作しませんでした。Preact X では、この障壁はもうなく、最新バージョンの styled-components
で動作します。react を preact に正しくエイリアスしていることを確認してください。
preact-portal
Portal
コンポーネントは preact/compat
の一部になりました。
preact-portal
を削除しますpreact/compat
からcreatePortal
をインポートします
コードの準備
名前付きエクスポートの使用
ツリーシェイキングをより適切にサポートするために、Preact コアではデフォルトのエクスポートは提供されなくなりました。このアプローチの利点は、必要なコードのみがバンドルに含まれることです。
// Preact 8.x
import Preact from "preact";
// Preact X
import * as preact from "preact";
// Preferred: Named exports (works in 8.x and Preact X)
import { h, Component } from "preact";
注: この変更は preact/compat
には影響しません。react との互換性を維持するために、名前付きエクスポートとデフォルトエクスポートの両方が引き続き含まれています。
render()
は常に既存の子を差分比較
Preact 8.x では、render()
の呼び出しは常に要素をコンテナに追加していました。
// Existing markup:
<body>
<div>hello</div>
</body>
render(<p>foo</p>, document.body);
render(<p>bar</p>, document.body);
// Preact 8.x output:
<body>
<div>hello</div>
<p>foo</p>
<p>bar</p>
</body>
Preact 8 で既存の子を差分比較するには、既存の DOM ノードを提供する必要がありました。
// Existing markup:
<body>
<div>hello</div>
</body>
let element;
element = render(<p>foo</p>, document.body);
element = render(<p>bar</p>, document.body, element);
// Preact 8.x output:
<body>
<div>hello</div>
<p>bar</p>
</body>
Preact X では、render()
は常にコンテナ内の DOM 子を差分比較します。したがって、コンテナに Preact でレンダリングされなかった DOM が含まれている場合、Preact はそれを渡された要素と比較しようとします。この新しい動作は、他の VDOM ライブラリの動作により近いものになります。
// Existing markup:
<body>
<div>hello</div>
</body>
render(<p>foo</p>, document.body);
render(<p>bar</p>, document.body);
// Preact X output:
<body>
<p>bar</p>
<div>hello</div>
</body>
React の render
メソッドの動作と完全に一致する動作が必要な場合は、preact/compat
によってエクスポートされた render
メソッドを使用します。
props.children
は必ずしも array
ではない
Preact X では、props.children
が常に array
型であることは保証できません。この変更は、Fragments
と子配列を返すコンポーネントに関する解析の曖昧さを解決するために必要でした。ほとんどの場合、それに気づかないかもしれません。props.children
で配列メソッドを直接使用する場合のみ、toChildArray
でラップする必要があります。この関数は常に配列を返します。
// Preact 8.x
function Foo(props) {
// `.length` is an array method. In Preact X when `props.children` is not an
// array, this line will throw an exception
const count = props.children.length;
return <div>I have {count} children </div>;
}
// Preact X
import { toChildArray } from "preact";
function Foo(props) {
const count = toChildArray(props.children).length;
return <div>I have {count} children </div>;
}
this.state
に同期的にアクセスしない
Preact X では、コンポーネントの状態は同期的に変更されなくなります。これは、setState
の呼び出し直後に this.state
から読み取ると、以前の値が返されることを意味します。代わりに、コールバック関数を使用して、以前の値に依存する状態を変更する必要があります。
this.state = { counter: 0 };
// Preact 8.x
this.setState({ counter: this.state.counter + 1 });
// Preact X
this.setState(prevState => {
// Alternatively return `null` here to abort the state update
return { counter: prevState.counter + 1 };
});
dangerouslySetInnerHTML
は子の差分比較をスキップ
vnode
にプロパティ dangerouslySetInnerHTML
が設定されている場合、Preact は vnode
の子の差分比較をスキップします。
<div dangerouslySetInnerHTML="foo">
<span>I will be skipped</span>
<p>So will I</p>
</div>
ライブラリ作成者向けの注意事項
このセクションは、Preact X で使用するパッケージを管理しているライブラリ作成者を対象としています。作成者でない場合は、このセクションをスキップしても問題ありません。
VNode
の形状が変更されました
次のプロパティの名前を変更/移動しました
attributes
->props
nodeName
->type
children
->props.children
できる限り努力しましたが、常に React 用に作成されたサードパーティライブラリでエッジケースが発生しました。この vnode
形状の変更により、発見困難なバグが多数なくなり、compat
コードが大幅にクリーンになりました。
隣接するテキストノードが結合されなくなった
Preact 8.x では、最適化として隣接するテキストノードを結合する機能がありました。DOM を直接比較しなくなったため、これは X には当てはまりません。実際、X ではパフォーマンスが低下することがわかったため、削除しました。次の例を見てみましょう
// Preact 8.x
console.log(<div>foo{"bar"}</div>);
// Logs a structure like this:
// div
// text
// Preact X
console.log(<div>foo{"bar"}</div>);
// Logs a structure like this:
// div
// text
// text