简介
第一个react17 RC版本发布时间:2020年8月11日
首先官方称react17的最大特点就是无新特性,react17版本主要目标是渐进式的去升级,它允许多版本混用共存,可以说是为更远的未来版本做准备了。也就是在大部分的场景下是没有太大的变化让你感知到的,但是也并不是一点都没有变:
- 异步的方式下获取事件 e 对象
- 事件委托到root节点
- 对一些浏览器事件做了小调整
- 全新的jsx转换器
- useEffect中返回函数(清除函数)的执行改为异步运行
- 报错信息更好的定位到对应源代码位置
- 启发式更新算法
1、去除事件池
什么叫事件池呢?
事件池:合成事件对象会被放入池中统一管理。这意味着合成事件对象可以被复用,当所有事件处理函数被调用之后,其所有属性都会被回收释放置空。
也就说你在React17 之前如果异步的方式直接去获取事件 e 对象显然是行不通的,他会被清除释放掉,所以在React17 之前你需要在异步方法中获取事件 e 得使用e.persist()
方法将当前的合成事件从事件池中删除,并允许保留对事件的引用,才可以在异步方法中引用 e
但是React17 就没有这个事件池东西了,也就不会去清空释放动作,你可以直接在异步中调用
function App() {
// v17 去除了 React 事件池,异步方式使用e不再需要 e.persist()
const handleClick = (e: React.MouseEvent) => {
console.log(e.target) // <button>React事件池</button>
setTimeout(() => {
// 如果是 v16 返回的是null
console.log(e.target) // <button>React事件池</button>
})
}
return (
<div className="App">
<button onClick={handleClick}>React事件池</button>
</div>
)
}
2、事件委托到根节点
React17 之前我们一般是把事件委托到document上,而在 React17 则是委托到根节点上,也就是说我们发生的事件源跟document是上下级的关系(document是上级),而不是同级的关系,也就是在 React17 后我们发生在react组件中的事件会冒泡到document上
3、部分事件调整
- onScroll 事件不再冒泡
- React 的 onFocus 和 onBlur 事件已在底层切换为原生的 focusin 和 focusout 事件,但是onFocus 事件总是冒泡的,在 React17 中会继续保持
4、useEffect副作用清理时机改为异步
在 React17 之前组件被卸载时,useEffect中清理函数都是同步运行的,而 React17 改为了异步执行
因此有一些点要注意,就是改成异步后一些ref.current的值可能为 null
了,对此要么你在它变为 null 之前先把它用变量存起来,要么用useLayoutEffect
,useLayoutEffect可以保证回调函数同步执行,这样就能确保 ref 此时还是最后的值
useLayoutEffect(() => {
demoRef.current.someSetupMethod()
return () => {
demoRef.current.someCleanupMethod()
}
})
上面这些是对开发中有感知的,或者是react16升级react17后需要考虑的点,接下来说一些无感知的
5、原生组件栈
react16 中错误调用栈的缺点:
- 缺少源码位置追溯,在控制台无法点击跳转到到出错的地方
- 无法适用于生产环境
整体来说不如原生的 JavaScript 调用栈,不同于常规压缩后的 JavaScript 调用栈,它们可以通过 sourcemap 的形式自动恢复到原始函数的位置,而使用 React 组件栈,在生产环境下必须在调用栈信息和 bundle 大小间进行选择。
在 v17 使用了不同的机制生成组件调用栈,直接从 JavaScript 原生错误栈生成的,所以在生产环境也能按 sourcemap 还原回来,且支持点击跳到源码位置。
想详细了解的可见该 PR
7、移除私有导出 API
v17 删除了一些私有 API,主要是 React Native for Web 使用的
另外,还删除了ReactTestUtils.SimulateNative工具方法,因为其行为与语义不符,如果你想要一种简便的方式来触发测试中原生浏览器的事件,可直接使用 React Testing Library
8、启发式更新算法更新
- React16 的
expirationTimes
模型只能区分是否>=expirationTimes
决定节点是否更新。 - React17 的
lanes
模型可以选定一个更新区间,并且动态的向区间中增减优先级,可以处理更细粒度的更新。