从 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
导入。它以前作为单独的包提供,但为了简化协调,我们已将其移至核心存储库。因此,你需要将现有的导入或别名声明从 preact-compat
更改为 preact/compat
(注意斜杠)。
小心不要在此处引入任何拼写错误。一个常见的错误似乎是将 compact
写成 compat
。如果你对此有疑问,可以将 compat
视为 react 的兼容
性层。这就是名称的由来。
如果你正在使用
preact-cli
,那么这一步已经为你完成了 :tada
第三方库
由于重大更改的性质,一些现有的库可能无法与 X 配合使用。其中大多数已根据我们的 beta 计划进行了更新,但你可能会遇到一个尚未更新的库。
preact-redux
preact-redux
就是尚未更新的此类库之一。好消息是 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 仅适用于 [email protected]
。使用 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()
始终对现有子项进行差异化
在 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
中读取将返回前一个值。相反,您应该使用回调函数来修改依赖于前一个值的 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