当前位置: 首页 > Web前端 > JavaScript

简单的React:探寻JSX的本质

时间:2023-03-27 17:02:24 JavaScript

前言JSX(JavaScriptXML)是学习React框架时必须了解的一个概念。虽然现在越来越多的人认可和支持JSX语法框架(比如Vue.js),但是当React第一次发布时和JSX一起发布的时候,还是引起了很大的争议,甚至有朋友直呼这是历史倒退.随着React框架的不断完善,JSX也被越来越多的开发者所认可,也越来越流行。变成了“真香”!本次分享将从以下三个问题入手:什么是JSX?JSX是做什么的?JSX的幕后发生了什么?在分享的过程中,我会尝试通过讲解一些demo代码和解读源码来寻找答案。希望通过这种方式帮助大家理解JSX,从根本上理解JSX,从而帮助我们写出更好的React。代码。JSX的本质:JavaScript语法扩展先来看看React官网是怎么定义JSX的:■JSX是JavaScript语法扩展。它看起来像一种模板语言,但它具有JavaScript的所有功能。刚接触JSX的同学普遍认为这是一种新的模板语言,因为它和通用的模板语言非常相似。我们通过三段功能相同的代码来直观感受一下://定义一些数据consttitle='hello'constlist=['a','b',c]constvisible=trueconstfootCssName='footer'Vue模板:{{title}}{{item}}

foot
EJS模板:<%=title%><%list.forEach(function(item){%>

<%=item%>

<%})%><%if(visible){%>">foot<%}%>
JSX语法:{title}{列表。map((item)=>{item}

)}{visible&&(foot)}
事实上,JSX不是模板语言,而是JavaScript语言的扩展。JSX是基于JavaScript语言的,所以具备了JS所有的能力(JS能做的,JSX什么都能做,比如表达式计算),但是增加了一些能力(JS不能做的,JSX也能做,比如自定义组件)。由于JSX是JavaScript的扩展,我们的浏览器无法解析原始的JSX代码,因为我们不知道它,那么JSX是如何工作的呢?其实React官网已经给出了答案(证明官网文档值得反复研究)■JSX会被编译成React.createElement(),React.createElement()会返回一个名为“React”的JS对象元素”。JSX需要编译,而编译这个动作是由Babel完成的。BabelBabel是一个工具链,主要用于将ECMAScript2015+版本的代码转换为向后兼容的JavaScript语法,使其可以在当前和旧版本的浏览器或其他环境中运行。//编译前constfirstName='Dan'constlastName='Abramov'conso.log(hello${firstName}${lastName}!)//编译后varfirstName="Dan";varlastName="Abramov";conso.log("你好".concat(firstName,"").concat(lastName,"!"));更多内容可以访问Babel官网了解。我们只需要知道Babel是一个翻译工具,它具有将JSX语法转换为JavaScript代码的能力。//https://babeljs.io/repl/{title}

内容

通过BabelREPL,我们可以看到JSX中的标签被转化为React.createElement函数调用,也就是说,其实写JSX就是写React.createElement函数,换句话说,JSX就是React.createElement的语法糖用于函数调用。JSX的作用:更好的React体验既然JSX只是React.createElement函数的一个语法糖,何不直接使用React.createElement写代码,这样可以省去Babel编译的一步。为了直观地理解使用JSX的好处,让我们看一下下面的代码:"app__three">

三文

四文

//===>///#__PURE__/标签是babel工具添加的//主要目的是告诉后续的代码压缩插件这里的代码是没有边的代码效果,所以你可以放心地优化它(已删除)//详情见:https://laysent.com/til/2019-.../#__PURE__/React.createElement('div',{className:'app',},/#__PURE__/React.createElement('div',{className:'app__one',},'一个文本',/#__PURE__/React.createElement('div',{className:'app__two',PU},/con__textRE'/React.createElement('div',{类sName:'app__three',},/#__PURE__/React.createElement('h2',null,'Threetext')),/#__PURE__/React.createElement('div',我们的名字{f__class:,}'/#__PURE__/React.createElement('p',null,'四文'))))),/#__PURE__/React.createElement(Hello,{name:"woqutech"}))React框架有一个著名的公式:UI=render(data),这个公式也是React理念的体现。用户看到的界面(UI)应该是一个函数(render)的执行结果。这个函数只接受data(数据)作为参数,而且这个函数是一个Purefunction(没有副作用,输出完全取决于输入,相同的输入必然得到相同的输出)。React认为渲染逻辑与其他UI逻辑是天生耦合的,比如在UI中绑定处理时间,触发回调更新数据,在UI中显示更新后的数据。如果只使用纯JavaScript代码来描述UI,那么在复杂的UI界面下,编写的代码可读性很差。我们使用大家最熟悉的HTML(HyperTextMarkupLanguage,超文本标记语言)标签语法来创建虚拟DOM,以降低学习成本的同时提高代码的可读性(清晰的层次结构、清晰的嵌套关系)和编码效率(借助工具自动补全和错误提示),这是JSX越来越流行的一个重要原因。JSX背后的处理:创建虚拟DOM节点前面说了,JSX是React.createElement函数的语法糖,那么React.createElement函数是做什么的呢?让我们仔细看看React源代码。注:本文提取的React源码来自16.8.6版本。·提示在githubrepo页面上,点击.键盘上的按键,可以启动在线IDE模式,获得更好的代码阅读体验。//packages/react/src/ReactElement.js//createElement有3个入参,包含了React创建元素需要知道的所有信息//type:用于标识节点的类型。可以是标准的HTML标签字符串,如“h1”或“div”,也可以是React组件类型或React片段类型//config:作为对象传入,组件的所有属性都会存储在键值对的形式在config对象中//children:作为对象传入,记录了组件标签之间嵌套的内容,也就是所谓的“子节点”和“子元素”exportfunctioncreateElement(type,config,children){//propName变量用来存放后面要用到的元素属性letpropName//props变量用来存放元素属性的键值对集合constprops={}//key,ref,self,source都是React元素的属性letkey=nullletref=nullletself=nullletsource=null//config对象存储元素的属性if(config!=null){//进入后首先要做的是依次修改ref,key,self和source属性赋值if(hasValidRef(config)){ref=config.ref//...}if(hasValidKey(config)){key=''+config.key}self=config.__self===undefined?空:config.__selfsource=config.__source===未定义?null:config.__source//下一步是将config中的所有属性移动到props,即之前声明的对象。for(propNameinconfig){if(hasOwnProperty.call(config,propName)&&!RESERVED_PROPS.hasOwnProperty(propName)){props[propName]=config[propName]}}}}//childrenLength指的是当前元素的子元素个数//减去2就是type和config这两个参数占用的长度constchildrenLength=arguments.length-2//如果只剩下一个参数,一般是文本节点if(childrenLength===1){//直接把这个参数的值赋给props.childrenprops.children=children}elseif(childrenLength>1){//声明一个子元素数组constchildArray=Array(childrenLength)//将子元素压入数组for(leti=0;i,document.getElementById('root'))ReactDOM.render(//要渲染的元素(ReactElement)element,//元素所在的目标容器ismounted(ArealDOMnode)container,//回调函数,可选参数,可用于处理渲染后的逻辑[callback])至此,我们就完成了从JSX到真实DOM的整个过程,我们还可以解读源码可以看出,这块内容其实比较简单,对我们理解JSX没有任何障碍。小结看完这篇文章,相信大家应该能够轻松回答开篇提出的三个问题。也欢迎大家在评论区写下自己的想法或问题,以便我们进一步探讨。参考资料https://babeljs.io/docs/en/ba...https://laysent.com/til/2019-...https://que01.top/2019/06/28/...