一、前言
本文基于开源项目:
广东靓仔总结下自己这几年对学习前端框架的一些想法,顺便讲讲React17带来的改变引起的一些个人想法。
在我们学习一门前端框架的时候,广东靓仔觉得官方文档一定是最好的学习资料。有些小伙伴可能把官方文档当作入门指南,然后再找其他学习资料去深度学习。广东靓仔觉得有点舍近求远了,官方文档一定是开发人员尽可能去写全、写精的。我们应该仔细的去阅读,而不是粗略看了一遍,然后找各种文章去阅读学习。
在这里广东靓仔可以很负责的说一句,市面上80%免费的文章,基本都是基于官方文档来写的。广东靓仔的文章也是如此,只不过是加了点自己的思考。
React官方文档写得特别好,还带着我们去领悟它的设计模式。
1.1 没有React基础可以开始用React17吗?
在React16.8版本引入了hook以来,React的学习成本就已经降低了很多了,我们可以通过函数式编程来开发我们的应用。React以前就像一艘“航母”一样,大而全。正因“全”因此我们的学习成本自然就高。有了hook我们使用函数组件开发,上手难度自然降低了很多。
二、React 17 带来了哪些改变
React17.0.1版本相对与16.8版本本身没有增加新特性,只是做了一些补充。17版本更像一个 基石
,为什么这么说呢?细心的小伙伴们会发现官方描述了这么一句话:“React v17 开启了 React 渐进式升级的新篇章”。这句话我看出了雄心勃勃,后续 18、19 等的更新版本一定是以17这个“基石”来开启新篇章。
这里列举让广东靓仔眼前一亮的两点:
1、新的 JSX 转换逻辑
2、事件系统重构
当然React17也有其他的更新,大家有兴趣可以去看官方文档。
三、重构 JSX 转换逻辑
React17之前我们如果这样写,代码如下:
function MyComponent() { return <p>前端早茶</p> }
页面是会报错的,why?
上一篇文章有讲到React 中对 JSX 代码的转换依赖的是 React.createElement 这个函数。有兴趣可以回头看下上一篇文章。
因此在写JSX的时候,是一定要在头部引入React的,代码如下:
import React from 'react'; function MyComponent() { return <p>前端早茶</p> }
React17之后我们在使用JSX,不再需要引入import React from 'react';
React17中编译器会自动帮我们引入 JSX 的解析器的,例如:
function MyComponent() { return <p>前端早茶</p> }
这个代码最后会被编译器转换为:
import {jsx as _jsx} from 'react/jsx-runtime'; function MyComponent() { return _jsx('p', { children: '前端早茶' }); }
react/jsx-runtime 中的 JSX 解析器帮我们完成了JSX的编译工作,很明显降低了我们的学习成本。如果有的小伙伴一开始就是从React17开始学习的,我们无感知的使用到它的方便。关于这块的内容,详细可以看看如下内容:
https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#motivation
四、事件系统重构
React17版本中事件系统重构可以分为两块来看:
- 放弃document 来做事件的中心化管控
- 放弃事件池
4.1 卸掉历史包袱
React之前是将所有事件冒泡到 document 来实现对事件的中心化管控,17版本放弃 document 来做事件的中心化管控。 why?因为有些时候合成事件虽然在 React 事件体系下的冒泡被阻止了,但是并不能够阻止原生 DOM 事件的冒泡。
React17中,事件管控相关的逻辑被转移到了每个 React 组件自己的容器 DOM 节点中,比如我们常写的在 ID 为 root 的 DOM 节点下挂载了一个 React 组件,代码如下:
const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
之后React 组件就只能自己管理自己的东东了,无法再影响到全局了。
4.2 拥抱新潮流
React 之前,合成事件对象都是被放进“事件池”统一管理,为了能够对事件对象的复用,提高性能。细心的小伙伴会发现,既然考虑到复用,事件处理函数执行完成后,合成事件对象内部的所有属性都会被置空。
那么问题来了,如果事件执行完成,我们想获取事件对象呢?
广东靓仔找来了官方的代码,来说明:
function handleChange(e) { // This won't work because the event object gets reused. setTimeout(() => { console.log(e.target.value); // Too late! }, 100); }
异步执行的 setTimeout 回调会在 handleChange 这个事件处理函数执行完毕后执行,因此它拿不到想要的那个事件对象 e了。
要想获取的话,我们就需要使用e.persist()
,代码如下:
function handleChange(e) { // Prevents React from resetting its properties: e.persist(); setTimeout(() => { console.log(e.target.value); // Works }, 100); }
React 17在研发体验上考虑比较多,官方放弃事件池,为每一个合成事件创建新的对象。所以之后我们不再需要编写 e.persist(),也可以随时随地访问我们想要的事件对象。
五、总结
在我们阅读完官方文档后,我们一定会进行更深层次的学习,比如看下框架底层是如何运行的,以及源码的阅读。
这里广东靓仔给下一些小建议:
- 在看源码前,我们先去官方文档复习下框架设计理念、源码分层设计
- 阅读下框架官方开发人员写的相关文章
- 借助框架的调用栈来进行源码的阅读,通过这个执行流程,我们就完整的对源码进行了一个初步的了解
- 接下来再对源码执行过程中涉及的所有函数逻辑梳理一遍