Hydration 2.0、ref の既定フォワード、フック引数の Object.is 比較が乗る。既存アプリの移行は型の厳格化が中心で、@preact/signals、preact-render-to-string、preact-iso、prefresh、@preact/preset-vite はプレリリース時点から 11 に対応済み。

#移行・破壊的変更

polyfill なしの対応ブラウザは Chrome 71 以上、Safari 12.1 以上、Firefox 69 以上、Edge 79 以上。TypeScript は 5.1 以上。コアとアドオンの配布は .mjs の ESM のみで、.module.js、CommonJS、UMD は削除。require(esm) 対応ランタイムは require('preact') のまま ESM を読み、preact/dist/preact.js などの直接参照は標準 ESM または ESM 向け CDN へ切り替える。preact/compat/server など一部の compat 入口は CommonJS ラッパを残す。

ref は既定でフォワードされ、preact/compat の forwardRef は不要。関数コンポーネントでは ref を他の prop と同様に受け取る。preact/compat では React に合わせクラスへはフォワードせず、純 Preact ではクラスにもフォワードする。旧配置が必要なら options.vnode で vnode.props.ref を vnode.ref へ戻す。

jsx
function MyComponent({ ref }) {
	return <h1 ref={ref}>Hello, world!</h1>;
}

<MyComponent ref={myRef} />;
// Preact 10: myRef.current is an instance of MyComponent
// Preact 11: myRef.current is the <h1> DOM element

数値 style の自動 px 付与は preact/compat へ移る。コアでは height: 500 が height:500 になる。

jsx
<h1 style={{ height: 500 }}>Hello World!</h1>
// Preact 10: <h1 style="height:500px">Hello World!</h1>
// Preact 11: <h1 style="height:500">Hello World!</h1>

フック引数の比較は Object.is。NaN を state や useEffect / useMemo / useCallback の依存にしても、Preact 10 のように毎回再レンダーしない。

そのほかは次のとおり。

  • defaultProps は preact/compat へ移る
  • render() の第 3 引数 replaceNode は削除。代替は preact-root-fragment の createRootFragment
  • Component.base は削除
  • SuspenseList は preact/compat から削除
  • アンマウント時の useEffect クリーンアップは paint 後。同期が必要なら useLayoutEffect
  • useRef は初期値が必須。null を含むなら型引数に含める

JSX 名前空間は TypeScript が要求する型のみ残し、それ以外は preact から import。

ts
// Preact 10
import { JSX } from 'preact';

type MyCustomButtonProps = JSX.ButtonHTMLAttributes & { ... }

// Preact 11
import { ButtonHTMLAttributes } from 'preact';

type MyCustomButtonProps = ButtonHTMLAttributes & { ... }

#Hydration 2.0

Preact X では async 境界が返す DOM ノードは 1 つに限られた。11 では 0 個、または 2 個以上も可。ストリーム SSR では suspended 境界が安定したコメントマーカーを使い、古い fallback ではなく最新のストリーム DOM に対して hydration を再開。

createPortal は preact から直接 import 可能。preact/compat からの export は残る。preact/compat には use()、useEffectEvent()、useSyncExternalStore() の任意引数 getServerSnapshot、Children.map / Children.forEach の任意 context が加わる。preact/debug は captureOwnerStack() と setupComponentStack() を export。

#参考文献