react 数字转字符_深入浅出 React -- JSX

什么是 JSX

JSX 是一个 JavaScript 的语法扩展。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能
在 React 中,JSX 仅仅是 React.createElement(component, props, ...children) 函数的语法糖

如下 JSX 代码:

<MyButton color="blue" shadowSize={2}>Clicke Me
</MyButton>

会编译为:

React.createElement(MyButton,{color: 'blue', shadowSize: 2},'Click Me'
)

React 必须在作用域内

由于 JSX 会编译为 React.createElement 调用形式,所以 React 库也必须包含在 JSX 代码作用域内

如果不使用打包工具而是直接通过 <script> 标签加载 React,则必须将 React 挂载到全局变量中

用户自定义的组件必须以大写字母开头

以小写字母开头的元素代表一个 HTML 内置组件,比如 <div> 或者 <span> 会生成相应的字符串 'div' 或者 'span' 传递给 React.createElement(作为参数)。大写字母开头的元素则对应着在 JavaScript 引入或自定义的组件,如 <Foo /> 会编译为 React.createElement(Foo)

JSX 语法

在 JSX 中嵌入表达式

在 JSX 语法中,你可以在打括号内放置任何有效的 JavaScript 表达式

function formatName(user) {return user.firstName + ' ' + user.lastName;
}const user = {firstName: 'Harper',lastName: 'Perez'
}const element = (<h1>Hello, {formatName(user)}!</h1>
)ReactDOM.render(element,document.getElementById('root')
)

JSX 也是一个表达式

在编译后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象

function getGreeting(user) {if (user) {return <h1>Hello, {formatName(user)}!</h1>;}return <h1>Hello, Stranger.</h1>;
}

JSX 特定属性

在属性中嵌入 JavaScript 表达式时,不要在大括号外面加上引号。你应该仅使用引号(对于字符串值)或大括号(对于表达式)中的一个,对于同一属性不能同时使用这两种符号。

const element = <img src={user.avatarUrl}></img>
因为 JSX 语法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小驼峰命名)来定义属性的名称,而不使用 HTML 属性名称的命名约定。

使用 JSX 指定子元素

假如一个标签里面没有内容,你可以使用 /> 来闭合标签,就像 XML 语法一样:

const element = <img src={user.avatarUrl} />

JSX 标签里能够包含很多子元素:

const element = (<div><h1>Hello!</h1><h2>Good to see you here.</h2></div>
)

JSX 防止注入攻击

React DOM 在渲染所有输入内容之前,默认会进行转义

所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。

JSX 表示对象

Babel 会把 JSX 转译成一个名为 React.createElement() 函数调用

以下两种示例代码完全等效:

const element = (<h1 className="greeting">Hello, world!</h1>
)const element = React.createElement('h1',{className: 'greeting'},'Hello, world!'
)

JSX 中的 Props

JavaScript 表达式作为 Props

<MyComponent foo={1 + 2 + 3 + 4} />

字符串字面量

以下两个 JSX 表达式是等价的:

<MyComponent message="hello world" /><MyComponent message={'hello world'} />

当你将字符串字面量赋值给 prop 时,它的值是未转义的

以下两个 JSX 表达式是等价的:

<MyComponent message="&lt;3" /><MyComponent message={'<3'} />

Props 默认值为 true

以下两个 JSX 表达式是等价的:

<MyTextBox autocomplete /><MyTextBox autocomplete={true} />

属性展开

可以使用展开运算符 ... 来在 JSX 中传递整个 props 对象。

以下两个组件是等价的:

function App1() {return <Greeting firstName="Ben" lastName="Hector" />;
}function App2() {const props = {firstName: 'Ben', lastName: 'Hector'};return <Greeting {...props} />;
}

JSX 中的子元素

包含在开始和结束标签之间的 JSX 表达式内容将作为特定属性 props.children 传递给外层组件。

有几种不同的方法来传递子元素:

字符串字面量

<MyComponent>Hello world!</MyComponent>

编译为:

<div>This is valid HTML &amp; JSX at the same time.</div>

JSX 会移除行首尾的空格以及空行。与标签相邻的空行均会被删除,文本字符串之间的新行会被压缩为一个空格。

因此以下的几种方式都是等价的:

<div>Hello World</div><div>Hello World
</div><div>HelloWorld
</div><div>Hello World
</div>

JSX 子元素

<MyContainer><MyFirstComponent /><MySecondComponent />
</MyContainer>

JavaScript 表达式作为子元素

JavaScript 表达式可以被包裹在 {} 中作为子元素。

以下表达式是等价的:

<MyComponent>foo</MyComponent><MyComponent>{'foo'}</MyComponent>

这对于展示任意长度的列表非常有用。例如,渲染 HTML 列表:

function Item(props) {return <li>{props.message}</li>;
}function TodoList() {const todos = ['finish doc', 'submit pr', 'nag dan to review'];return (<ul>{todos.map((message) => <Item key={message} message={message} />)}</ul>);
}

函数作为子元素

你可以将任何东西作为子元素传递给自定义组件,只要确保在该组件渲染之前能够被转换成 React 理解的对象。这种用法并不常见,但可以用于扩展 JSX。

function Item(props) {return <li>{props.message}</li>;
}function TodoList() {const todos = ['finish doc', 'submit pr', 'nag dan to review'];return (<ul>{todos.map((message) => <Item key={message} message={message} />)}</ul>);
}

布尔类型、Null 以及 Undefined 将会忽略

false, null, undefined, and true 是合法的子元素。但它们并不会被渲染。

以下的 JSX 表达式渲染结果相同:

<div /><div></div><div>{false}</div><div>{null}</div><div>{undefined}</div><div>{true}</div>

这有助于依据特定条件来渲染其他的 React 元素。例如,在以下 JSX 中,仅当 showHeadertrue 时,才会渲染 <Header /> 组件:

<div>{showHeader && <Header />}<Content />
</div>

值得注意的是有一些 “falsy” 值,如数字 0,仍然会被 React 渲染。例如,以下代码并不会像你预期那样工作,因为当 props.messages 是空数组时,0 仍然会被渲染:

<div>{props.messages.length &&<MessageList messages={props.messages} />}
</div>

要解决这个问题,确保 && 之前的表达式总是布尔值:

<div>{props.messages.length > 0 &&<MessageList messages={props.messages} />}
</div>

反之,如果你想渲染 falsetruenullundefined 等值,你需要先将它们转换为字符串

<div>My JavaScript variable is {String(myVariable)}.
</div>

JSX 的本质:JavaScript 的语法扩展

React 官网给出的一段定义:

JSX 是一个 JavaScript 的语法扩展。JSX 可能会使人联想到模版语言,但它具有 JavaScript 的全部功能

那么 “JSX 语法时如何在 JavaScript 中生效的

JSX 语法是如何在 JavaScript 中生效的:认识 Babel

JSX 定位是 JavaScript 的“扩展”,这就直接决定了浏览器不会天然支持 JSX。那么,JSX 的语法是如何在 JavaScript 中生效的呢?React 官网给出了答案:

JSX 会被编译为 React.createElement(), React.createElement() 将返回一个叫作“React Element”的 JS 对象。

“编译” 这个动作,是由 Babel 来完成的

什么是Babel

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。 —— Babel 官网

例如箭头函数:

// Babel 输入: ES2015 箭头函数
[1, 2, 3].map((n) => n + 1);// Babel 输出: ES5 语法实现的同等功能
[1, 2, 3].map(function(n) {return n + 1;
});

类似的,Babel 也具备将 JSX 语法转换为 JavaScript 代码的能力

看看开头的示例:

649211fb1282efe31c90c82df2a6085f.png

我们写的 JSX 其实写的就React.createElement,虽然它看起来有点像 HTML,但也只是“看起来像”而已。JSX 的本质是 React.createElement 这个 JavaScript 调用的语法糖,这也呼应了 React 官方给出的“JSX 充分具备 JavaScript 的能力”这句话。

为什么选择 JSX

既然 JSX 等价于一次 React.createElement 调用,为什么不直接使用 React.createElement 来创建元素呢?

原因很简单,在效果一致的前提下,JSX 代码层次分明、嵌套关系清晰,而 React.createElement 代码混乱杂糅,不仅难以阅读,也难以编码

JSX 语法糖允许前端开发者使用我们最为熟悉的类 HTML 标签语法来创建虚拟 DOM,在降低学习成本的同时,也提升了研发效率与研发体验。

React 官网也提出:

React 并没有采用将标记与逻辑进行分离到不同文件这种人为地分离方式,而是通过将二者共同存放在称之为“组件”的松散耦合单元之中,来实现关注点分离

JSX 是如何映射为 DOM 的:阅读 createElement 源码

我们先大致理解 createElement 函数源码的作用:

//注意:react只写了3个参数,实际上,从第三个参数往后都是children
export function createElement(type, config, children) {let propName; // 用于存储后面需要用到的元素属性// Reserved names are extractedconst props = {}; // 用于存储元素属性的键值对集合let key = null;let ref = null;let self = null;let source = null;// 赋给标签的props不为空时// config 存储元素的属性if (config != null) {// 依次对 ref、key、self 和 source 属性赋值if (hasValidRef(config)) {ref = config.ref;}if (hasValidKey(config)) {// 防止是Numberkey = '' + config.key;}//__self、__source 暂时不知道是干啥用的属性self = config.__self === undefined ? null : config.__self;source = config.__source === undefined ? null : config.__source;// Remaining properties are added to a new props objectfor (propName in config) {// 如果config中的属性不是标签原生属性,则放入props对象中if (hasOwnProperty.call(config, propName) &&!RESERVED_PROPS.hasOwnProperty(propName)) {props[propName] = config[propName];}}}// Children can be more than one argument, and those are transferred onto// the newly allocated props object.// 子元素数量const childrenLength = arguments.length - 2;if (childrenLength === 1) {props.children = children;} else if (childrenLength > 1) {const childArray = Array(childrenLength);// 依次将children push进array中for (let i = 0; i < childrenLength; i++) {childArray[i] = arguments[i + 2];}// 开发中写的this.props.children就是子元素的集合props.children = childArray;}// Resolve default props// 为传入的props设置默认值,比如://class Comp extends React.Component{//  static defaultProps = {//     aaa: 'one',//     bbb: () => {},//     ccc: {},//   };//// }if (type && type.defaultProps) {const defaultProps = type.defaultProps;for (propName in defaultProps) {// 如果props数组中未设值,则设置默认值(注意:null也算设置了值)if (props[propName] === undefined) {props[propName] = defaultProps[propName];}}}return ReactElement(type,  //'div'key,  //nullref,  //nullself, //nullsource, //nullReactCurrentOwner.current, // null或Fiberprops, // 自定义的属性、方法,注意:props.children=childArray);
}

参数:创建一个元素需要哪些信息

export function createElement(type, config, children)
  • type:用于表示节点的类型。它可以是标准 HTML 标签字符串,也可以是 React 组件类型或 React Fragment 类型
  • config:以对象形式传入,组件所有的属性都会以键值对的形式存储在 config 对象中
  • children:以对象形式传入,它记录的是组件标签之间嵌套的内容,也就是所谓的 “子节点” “子元素”

下面的示例可以帮助增进对 createElement 的理解:

React.createElement('div', {className: 'wrapper'
}, React.createElement('h1', {className: 'header'
}, 'header'), React.createElement('p', {className: 'content'
}, 'content'))

对应的 DOM 结构:

<div class="wrapper"><h1 class="header">header</h1><p class="content">content</p>
</div>

createElement 分析

逻辑流程图

10fb17d3ca4e6380aa2e86d662ecf0ce.png

createElement 中并没有复杂的逻辑,它的每一步步骤几乎都是在格式化数据

createElement 就如同是开发者和 ReactElement 调用之间的一个 “转换器”,对数据进行处理

返回值:初识虚拟 DOM

createElement 执行到最后会 return 一个 ReactElement 的调用

下面是关于 ReactElement 的源码及解析:

const ReactElement = function(type, key, ref, self, source, owner, props) {const element = {// REACT_ELEMENT_TYPE是一个常量,用来标识该对象是一个ReactElement$$typeof: REACT_ELEMENT_TYPE,// 内置属性赋值type: type,key: key,ref: ref,props: props,// 记录创造该元素的组件_owner: owner,};if (__DEV__) {}return element;
};

ReactElement 只做了一件事,那就是创建ReactElement 把传入的参数按照一定的规范,“组装”进 element 对象,并将它返回给 React.createElement,最终 React.createElement 又将它返回到开发者

对于 ReactElement 对象实例,其本质上是以 JavaScript 对象形式存在的对 DOM 的描述,也就是 “虚拟 DOM”(更准确地说,是虚拟 DOM 中的一个节点)

从虚拟 DOM 到真实 DOM 需要调用 ReactDOM.render 方法

在每个 React 项目的入口文件中,都有对 React.render 函数的调用。下面是 ReactDOM.render 的函数签名:

ReactDOM.render(// 需要渲染的元素(ReactElement)element,// 元素挂载的目标容器(真实 DOM)container,// 回调函数,用于处理渲染结束后的逻辑。可选[callback]
)

总结

JSX 经过 babel 转换为 React.createElement 函数,再调用 React.createElementReactElement 返回一个 element 对象(虚拟 DOM),最后通过 React.render 函数的调用,生产真实 DOM 节点并挂载到 “容器” 上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307055.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mybatis mysql schema_MyBatis学习 之 一、MyBatis简介与配置MyBatis+Spring+MySql

一、MyBatis简介与配置MyBatisSpringMySql1.1MyBatis简介MyBatis 是一个可以自定义SQL、存储过程和高级映射的持久层框架。MyBatis 摒除了大部分的JDBC代码、手工设置参数和结果集重获。MyBatis 只使用简单的XML 和注解来配置和映射基本数据类型、Map 接口和POJO 到数据库记录。…

.NET架构小技巧(7)——做好小的项目

一屋不扫&#xff0c;何以扫天下。再说也没有那么多天下(大系统)可扫&#xff0c;更多的是一个个自己居住的小屋(手边的小项目&#xff0c;子模块)&#xff0c;所以认真的开始扫自己的小屋。在visual studio中&#xff0c;解决方案(Solution)下可以创建多个项目(Project)&#…

使用 C# 9.0 新语法提升 if 语句美感

C# 语言一贯秉承简洁优美的宗旨&#xff0c;每次升级都会带来一些语法糖&#xff0c;让我们可以使代码变得更简洁。本文分享两个使用 C# 9.0 提升 if 语句美感的技巧示例。使用属性模式代替 IsNullOrEmpty在任何你使用 IsNullOrEmpty 的时候&#xff0c;可以考虑这样替换&#…

在 Azure App Service 上启用 Application Request Routing

点击上方蓝字关注“汪宇杰博客”导语我们在IIS上经常使用 Application Request Routing (ARR) 模块做反向代理。Azure App Service 使用的也是 IIS&#xff0c;照理来说应该也能做反代&#xff0c;但默认情况下它是不行的&#xff0c;我们来看看如何给在 App Service 上启用 AR…

【专题】多角度深入解析开放原子开源基金会

喜欢就关注我们吧&#xff01;2020 年 9 月 9 日&#xff0c;开放原子开源基金会正式对外发声&#xff0c;同天&#xff0c;宣布百度超级链正式成为基金会首个捐赠项目。9 月 10 日&#xff0c;华为 OpenHarmony 操作系统开源&#xff0c;开放原子开源基金会获捐 OpenHarmony。…

C#刷剑指Offer | 【常考题】最小的k个数

【C#刷题】| 作者 / Edison Zhou这是EdisonTalk的第299篇学习分享我们来用之前学到的数据结构知识来刷《剑指Offer》的一些核心题目&#xff08;精选了其中30道题目&#xff09;&#xff0c;希望对你有帮助&#xff01;本文题目为&#xff1a;最小的k个数。1题目介绍题目&#…

晶振噪声及杂散_晶振如何匹配电容看了就知道

描述一、什么是晶振了解晶振之前&#xff0c;我们先来看一下我们最为熟悉的51单片机&#xff0c;我们都知道51单片机最小系统包括供电电源、复位电路以及晶振系统。这是CPU能跑起来的最基本条件。由此我们可以看到晶振在电路当中的作用&#xff0c;那就是晶振电路用于产生时间频…

C# 中的 ref 已经被放开,或许你已经不认识了

一&#xff1a;背景 1. 讲故事最近在翻 netcore 源码看&#xff0c;发现框架中有不少的代码都被 ref 给修饰了&#xff0c;我去&#xff0c;这还是我认识的 ref 吗&#xff1f;就拿 Span 来说&#xff0c;代码如下&#xff1a;public readonly ref struct Span<T>{public…

java中file_详细介绍Java中的File类

构造方法File f new File("文件路径")File f new File("parent","child")创建一个文件&#xff1a;//在工作空间目录下创建a.txt的文件File f new File("a.txt");f.createNewFile();在G:\路径下创建一个a.txt的文件.如果已经有的话…

.NET5全面拥抱Azure云,微软市值重回巅峰,那些年吹过的牛,都实现了!

“Microsoft Azure的重要性在于&#xff0c;它是继Windows取代DOS之后&#xff0c;微软的又一次颠覆性转型——通过在互联网架构上打造全新计算平台&#xff0c;使得Windows真正由PC和服务器延伸到“蓝天”上。” ------曾微软全球副总裁张亚勤2014年2月&#xff0c;纳德拉成为…

大象起舞——微软研发如何保持创新力和敏捷性

我有幸见证微软在近五年的变革&#xff0c;也作为局内人学习如此一个全球性的、庞大的研发团队是如何管理、自我调整和创新的。上周五应邀给一个大客户的研发中心做了一个分享&#xff0c;其中我深刻地认识到有几点创新是一种文化。作为企业需要用心营造这样一种文化&#xff0…

java 云架构_java版Spring Cloud云架构代码结构构建

本篇我们根据架构图进行代码的构建。根据微服务化设计思想&#xff0c;结合spring cloud一些优秀的项目&#xff0c;如服务发现、治理、配置化管理、路由负载、安全控制等优秀解决方案&#xff0c;使用Maven技术将框架进行模块化、服务化、原子化封装并构建&#xff0c;也为后期…

集赞有礼!进击吧! Blazor !第六期 企业内部应用建设实战

集赞有礼转发此文章至朋友圈&#xff0c;截止至直播结束前&#xff1a;集赞满20个&#xff0c;可获得Blazor贴纸&#xff1b;集赞满50个&#xff0c;可获得微软帆布包&#xff1b;集赞满88个&#xff0c;可获得笔记本&#xff1b;集赞最多的一位小伙伴将获得充电宝哦&#xff0…

基于阿里云日志服务快速打造简版业务监控看板

前言 最近老黄一直在弄双11相关的东西&#xff0c;所以博客和github都没怎么更新&#xff0c;这期间在公司也弄了不少东西。下面就简单分享一下最近做的业务监控相关的内容吧。先来说一下背景。某业务在双11第一波大促的时候因为没有提供实时的业务看板&#xff0c;总结会的时候…

一个.NET Core下的开源插件框架Pluginfactory

插件模式历史悠久&#xff0c;各种中大型软件基本上都会实现插件机制&#xff0c;以此支持功能扩展&#xff0c;从开发部署层面&#xff0c;插件机制也可实现功能解耦&#xff0c;对于并行开发、项目部署、功能定制等都有比较大的优势。在.NET Core下&#xff0c;一般我们基于.…

谈谈.NET Core IServiceProvider

【导读】最近重构部分代码&#xff0c;因历史原因在静态类中需使用注入实例&#xff0c;构造函数注入则不再可取&#xff0c;此时只能构造全局IServiceProvider&#xff0c;所以本文稍微分析下IServiceProvider要构造全局使用IServiceProvider&#xff0c;我们都知道不能在Conf…

使用 Xunit.DependencyInjection 改造测试项目

使用 Xunit.DependencyInjection 改造测试项目Intro这篇文章拖了很长时间没写&#xff0c;之前也有介绍过 Xunit.DependencyInjection 这个项目&#xff0c;这个项目是由大师写的一个 Xunit 基于微软 GenericHost 和 依赖注入实现的一个扩展库&#xff0c;可以让你更方便更容易…

discuz mysql data_Discuz!显示 Database Error的原因和解决方法

今天打开Discuz搭建的论坛显示&#xff1a;原因一&#xff1a;数据库表太大比如mysql数据库的表内容太大&#xff0c;超过10G就有可能会影响discuz论坛的运行。Discuz! Database Error是什么原因&#xff0c;怎么修复这种情况可以通过对数据库分表的方法来解决。原因二&#xf…

项目开发中经常有一些被嫌弃的小数据,现在全丢给 FastDFS

在我们开发项目的时候&#xff0c;经常会遇到大块数据的问题&#xff08;2M-100M&#xff09;&#xff0c;比如说保存报表中1w个人的ID号&#xff0c;说实话&#xff0c;这些数据存储在服务器哪里都被嫌弃&#xff0c;放在redis&#xff0c;mongodb中吧&#xff0c;一下子你就会…

java 反射 int_Java 反射由浅入深 | 进阶必备

原标题&#xff1a;Java 反射由浅入深 | 进阶必备一、Java 反射机制参考了许多博文&#xff0c;总结了以下个人观点&#xff0c;若有不妥还望指正&#xff1a;Java 反射机制在程序运行时&#xff0c;对于任意一个类&#xff0c;都能够知道这个类的所有属性和方法&#xff1b;对…