從 Preact 8.x 升級
本文件旨在指導您將現有的 Preact 8.x 應用程式升級到 Preact X,並分為 3 個主要部分
Preact X 帶來了許多令人興奮的新功能,例如 片段
、Hook
,以及與 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
匯入。它以前是作為一個獨立的套件提供,但為了簡化協調,我們已將它移至核心儲存庫。因此,您需要將現有的匯入或別名宣告從 preact-compat
變更為 preact/compat
(請注意斜線)。
小心不要在此處輸入任何拼寫錯誤。常見的錯誤是將 compat
寫成 compact
。如果您遇到此問題,請將 compat
視為 react 的相容性層。這就是名稱的由來。
如果您使用
preact-cli
,則此步驟已為您完成 :tada
第三方函式庫
由於重大變更的特性,某些現有的函式庫可能無法與 X 搭配使用。其中大部分已依照我們的 beta 排程進行更新,但您可能會遇到尚未更新的函式庫。
preact-redux
preact-redux
就是其中一個尚未更新的函式庫。好消息是 preact/compat
更符合 React,並可與稱為 react-redux
的 React 繫結搭配使用。切換到它將能解決此問題。請確定您已在 bundler 中將 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
讓您的程式碼準備好
使用命名匯出
為了更好地支援 tree-shaking,我們不再在 preact 核心提供 default
匯出。此方法的優點是,您的套件只會包含您需要的程式碼。
// 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()
始終對現有子項進行 diff
在 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
和傳回子元素 array
的元件的解析歧義是必要的。在多數情況下,您可能甚至不會注意到它。只有在您直接對 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 中,我們有此功能,其中我們將相鄰的文字節點合併作為最佳化。這不再適用於 X,因為我們不再直接與 DOM 進行比較。事實上,我們注意到它損害了 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