原文地址:www.preactjs.com.cn/guide/v10/d…
Main differences
Preact和React最主要的区别是Preact没有使用React的合成事件机制,而是使用了浏览器标准的addEventListener去注册事件。意味着在Preact中事件的命名和表现和在JavaScript/DOM中是一致的
- 事件不会通过
<Protal>组件冒泡
- 在使用表单输入是应该使用标准的
**onInput**而不是React的onChange (添加preact/compat后可使用) - 双击事件应该使用标准的
onDblClick而不是React的onDoubleClick (添加preact/compat后可使用) **onSearch**通常被用在<input type="search">,因为在IE11上清除按钮不会触发onInput事件
另一个值得注意的区别在于Preact更加遵循DOM规范,自定义标签的支持和其他的标签一样,自定义事件也是支持的,同时自定义事件命名区分大小写(和在DOM中一样)
Version Compatibility
对于preact和preact/compat,版本兼容性都是按照现在和之前React的主要版本来支持的。当React团队推出新特性之后,如果它们符合preact的项目目标,那么也会被加入到preact的核心代码中。这是一个完全民主的过程,通过在open、using issues 和 pull request中进行讨论和决策
因此,本网站和文档在讨论兼容性或进行比较时参考了React 16.x 和 15.x
Debug messages and errors
我们灵活的架构允许使用任意形式的插件来提升Preact的体验。例如preact/debug这个插件,添加了一些有帮助的warnings和errors,同时还有React Developer Tool 浏览器拓展插件。这会帮助你在开发Preact应用的时候更简单地观察到程序的运行情况。你可以通过下面的方式进行引用
import "preact/debug"; // <-- Add this line at the top of your main entry file
与React不同的是React需要在编译打包的时候通过**NODE_ENV != "production"** 来判断是否输出调试信息
Features unique to Preact
Preact添加了一些受(P)React社群工作启发的方便特性
Native support for ES Modules
为了方便,我们去除掉了在render方法中this.props 和 this.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>;
}
}
两种写法最终渲染结果都是一样的,render函数参数提供了更便利的写法
Raw HTML attribute/property names
Preact指在遵循大多数浏览器支持的DOM规范。当给一个元素设置props的时候,Preact会把所有的prop作为属性或者HTML属性都添加到元素上。这样就可以在自定义元素上设置复杂的属性,同时你也可以像这样在JSX中使用class
// This:
<div class="foo" />
// ...is the same as:
<div className="foo" />
大多数Preact开发者更喜欢用class,因为它写起来更短,但是两种写法都支持。
SVG inside JSX
SVG 在属性和属性的名称方面非常有趣。SVG 对象上的一些属性(及其属性)是驼峰式的(e.g. clipPathUnits on a clipPath element),一些属性是中划线的(e.g. clip-path on many SVG elements),其他的一些属性(通常是继承自DOM,e.g. 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属性名称
Use onInput instead of onChange
很大程度上因为历史原因,React 的 onChange 事件的语义其实和浏览器提供的 onInput 事件是一样的,到处都可以支持。**input**事件是你最希望在修改表单控件时做出响应的事件。在 Preact 核心中,onChange 是标准的 DOM 更改事件,当用户提交元素的值时会触发该事件
// React
<input onChange={e => console.log(e.target.value)} />
// Preact
<input onInput={e => console.log(e.target.value)} />
如果你使用preact/compat,大多数onchange事件在内部被转换成了oninput事件,用来模拟React的行为。这是我们用来确保与 React 生态系统最大兼容性的技巧之一。
JSX Constructor
JSX 是JavaScript的语法扩展,可转换为嵌套函数调用。使用这些嵌套调用来构建树结构的想法早在JSX之前就已经存在,并且之前在JavaScript中被hyperscript项目推广。这种方法论的价值远远超出了React生态系统本身的价值,因此Preact推广了最初的通用社区标准。要更深入地讨论 JSX 及其与 Hyperscript 的关系,请阅读这篇关于 JSX 工作原理的文章。
Source: (JSX)
<a href="/">
<span>Home</span>
</a>
Output:
// Preact:
h(
'a',
{ href:'/' },
h('span', null, 'Home')
);
// React:
React.createElement(
'a',
{ href:'/' },
React.createElement('span', null, 'Home')
);
最终,如果你正在查看为Preact应用程序生成的输出代码,很明显更短的未命名空间的“JSX pragma”既更易于阅读,也更适合像减少代码这样的优化。在大多数 Preact 应用程序中,你会遇到 h()函数,尽管你使用哪个名称并不重要,因为Preact还提供了createElement别名导出
No contextTypes needed
旧版Context API要求组件使用React的contextTypes或childContextTypes声明特定属性,以便接收这些值。Preact没有这个要求:默认情况下所有组件都接收getChildContext()产生的所有上下文属性。
Features exclusive to preact/compat
preact/compat 是我们将React代码转换为Preact的兼容层。对于现有的React用户来说,这是一种在不更改任何代码的情况下尝试Preact的简单方法,通过在编译器配置中设置一些别名
Children API
**Children** API 是一组专门的方法,用于处理 props.children 的值。对于Preact,这通常是不必要的,我们建议使用内置的数组方法。在 Preact 中,props.children要么是一个虚拟 DOM 节点,要么是一个空值,比如null,要么是一个虚拟DOM节点数组。前两种情况是最简单和最常见的,因为可以按原样使用或返回**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 提供了一个 toChildArray() 方法,该方法接受任何 props.children 值并返回一个扁平化和规范化的虚拟 DOM 节点数组
// 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>
}
preact/compat 提供了与 React 兼容的 Children API,以无缝集成现有的组件库
Specialised Components
preact/compat 附带了一些不是每个应用程序都需要的专用组件,包括
- PureComponent:只在state或者props发生改变的时候做更新
- memo:和PureComponent功能一致,不过只能应用在函数组件
- fowardref:为指定的自组件提供 ref
- Portals:继续将当前树渲染到不同的 DOM 容器中
- Suspense:实验性的 允许在树未准备好的情况下显示兜底内容
- lazy:实验性的 延迟加载异步代码并相应地将树标记为就绪/未就绪