前言
一些废话和个人感悟,看干货的直接跳过….到jsx
重识前端断断续续也写了大半年了。里面基本上都是个人技术栈的积累,以及面试题的回答。感兴趣的伙伴可以点到我的主页去看。
说说今天的主角-React
吧。React
的源码之前一直想要去阅读学习的,也确确实实在看了,但是经常看着看着就发困。然后就开始偷懒,从一些周边的开始阅读,比如React-Router
,React-Redux
之类的。之前都是看完之后再开始写文章。现在想一边看一边写,换个方式看看。如果有写错的地方欢迎大家讨论,如果觉得还可以的话可以点个赞,谢谢!
作为一名React
的重度使用者和爱好者。我将会和大家一起从「使用者」到「了解者」进步!
React的相关信息
功利的角度
打开招聘软件,现在基本上的大厂,甚至是外包公司都普遍要求你会React
或者Vue
。给出的薪资也是非常的诱人。
(图片来自Boss某聘)
为了发财这个朴实的梦想也应该学习。
学习的角度
如今前端御三家:Angular
、React
、Vue
三分天下。国内更青睐React
和Vue
。所以,从学习的角度更应该学习React
。
https://www.npmtrends.com/react-vs-vue-vs-@angular/core
为什么非要学习源码
这个问题我之前也问过,几乎所有的面试都是造火箭,工作拧螺丝。
我认为从两个角度来看这个问题:
- 应聘者
- 吃透
React
的情况下,解决问题的上限肯定是提高了 - 一个优秀的框架是一位优秀的老师
- 吃透
- 招聘者,既然都是能干活的,我就找一个懂得更多的人来干这个活
JSX
废话不多说,直接开始。
JSX,再熟悉不过了,日常使用React过程中肯定会用到的。给一个demo,帮大家回一下。
1 | import React from "react"; |
我先问几个问题,如果能够清晰的快速答出来,那么恭喜你,你的基础很扎实,如果不行,那就一起看看,看完之后可以把你的答案写在评论区,和大家讨论。
- 什么是
JSX
?JSX
和JS
有什么关系? JSX
的底层原理是什么?- 为什么
React
要选择JSX
?
带着问题一起来看。
什么是JSX
先看看React
官网的一句话。
1 const element = <h1>Hello, world!</h1>;它被称为 JSX,是一个 JavaScript 的语法扩展。
语法扩展,意思就是JS
有的他都有的情况下,还有一些别的功能。可是这货,明显在JavaScript
学习过程中没见过他呀。他能运行在JavaScript
的环境中吗?打开Chrome
控制台。
上来就是劈头盖脸的语法错误,看样子这部分就是多出来的功能了呗。那咋运行啊?
1 | { |
怎么样,熟悉不,意思是告诉webpack
,解析jsx
结尾的代码,需要用到babel
。ok,也就是说要想运行jsx
,就必须用babel
解析。那好,什么是babel?
babel
拉一段babel
官网上的一句话
Babel 是一个 JavaScript 编译器
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
babel
,其实就是帮我们解析我们写的代码,然后变成浏览器能够认识样式。比如jsx
,比如新鲜的es6
语法可以运行在老版本的浏览器上,让老版本的浏览器能够认识。
那问题又来了,jsx被babel变成什么样子了?
大家可以把上面的小demo,扔进去。
发现没有。我们return
出去的东西变成了React.createElement
。哈哈,这就是为什么我们即使没有用到React
(解决了一到面试题!),也需要在上面import
,因为jsx
最后是会被转化为React.createElement
,会用到的!(不过现在最新的好像不需要引用也不会报错了,因为他自己识别了。
官网介绍:https://zh-hans.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
1
2
3
4
5
6 // 由编译器引入(禁止自己引入!)
import {jsx as _jsx} from 'react/jsx-runtime';
function App() {
return _jsx('h1', { children: 'Hello world' });
}注意,此时源代码无需引入 React 即可使用 JSX 了!(但仍需引入 React,以便使用 React 提供的 Hook 或其他导出。)
回到之前React
官网提到的
它被称为 JSX,是一个 JavaScript 的语法扩展。
有没有呼应起来了,确实js
他都有,但是js
没有的,他还有比如转化为React.createElement
。
createElement
我们是来读源码学习的,我们既然知道了jsx
的底层是调用react
的函数,我们就来看看这个函数是个什么情况。
1 | export function createElement(type, config, children) { |
先不看参数,我们就先看返回值的名字和这个函数的名字。我们初步猜测,jsx
是通过createElement
这个函数来创建一个React
元素,然后由ReactDOM.render
来渲染到我们指定名字的元素上。
ok,那么我们平常写的jsx元素就是ReactElement
生成的东西。我们看看ReactElement
生成的是个什么东西。
我们先把我们平常写的jsx
给打印一下。
凭直觉,是不是感觉这个是一个虚拟DOM
的节点,他有类型然后又是div
,对应的会不会是html
的div
标签?还有className
,这个很明显就是对应class
。我们去一看究竟。
ReactElement
1 | const ReactElement = function(type, key, ref, self, source, owner, props) { |
看过之后,是不是和我们看到的节点一样,首先,标注一下$$typeof
为react节点
。然后就是正常的传参,比如key
,ref
,props
等等。
ReactDOM.render
这个就是React节点渲染为真是节点的操作。话不多说,上源码!
1 | export function isValidContainer(node: mixed): boolean { |
有没有感觉很简单,去除__DEV__
情况的话。也是返回一个函数的结果。。。
ReactDOM.hydrate
这个函数我发现很有意思,与ReactDOM.render只有一行代码不一样
1 | legacyRenderSubtreeIntoContainer( |
首先,这个hydrate
的意思是注水。大致的意思是给一个结点增加水分,增添色彩。之前是给SSR
过程中添加点击事件之类使用的。在React17
之后会淘汰掉ReactDOM.Render
,全部用ReactDOM.hydrate
来代替。
React官网的一句话
使用
ReactDOM.render()
对服务端渲染容器进行 hydrate 操作的方式已经被废弃,并且会在 React 17 被移除。作为替代,请使用hydrate()
。
为什么要使用JSX
这里分享一个解题的小技巧。为什么要XX其实就是要问你,XX的好处。ok,那接下来就很好回答了
首先,因为如果不用jsx
,我们就要在代码里面写上百个React.crearteElement
。
第二,这个语法糖可以让开发者使用熟悉的HTML
标签来创建虚拟DOM
,降低学习成本。提升开发效率与开发体验
剩余的坑
- legacyRenderSubtreeIntoContainer(涉及fiber架构
- _owner(创建的时候,这个属性有什么用