详情参考官方JSX规范

虽然JSX是扩展到ECMAScript的类XML语法,但是它本身并没有定义任何语义。也就是说它本身不在ECMAScript标准范围之内。它也不会被引擎或者浏览器直接执行。通常会利用很编译器预处理器来将这些JSX转化为标准的ECMAScript。

吐槽:虽然JSX出发点是好的,而且写起来也很简单,但是对于要在JS中写类HTML格式的内容,我的内心是排斥的,感觉非常不习惯。这不是我熟知的web开发啊!有种在开发app的感觉,一个个自定义的组件。

想看看他是怎么编译JSX,于是我看了下用JS的写法写组件,主要的方法就是React.createElement

React.createElement(
type,
[props],
[...children]
)

第一个参数type是类型,也就是名字,比如h1div自定义组件名等~

第二个参数[props]其实就是各种属性,我们在JS中怎么写属性的,在这里就怎么写。比如img.src="",div.className=""这样的,那么属性就是这么写的{className:"",src:""},属性名和JS保持一致。

第三个参数,其实就是无限延展当前节点的子节点,你想有多少个就有多少个。

来看一眼官方文档的转化,这个是我用React.createElement来转义的JSX,这样一个套一个的写法,什么时候才是个头。强烈的求生欲使我放弃了JS的写法,转投JSX的写法了:

相比较这种无限嵌套的写法,JSX友善太多了。从语义化的角度来说,JSX的可读性也是很好滴。(为自己学习JSX强行找理由。)

深入了解JSX的对象

上一节提到,

let element=<h1 className="aaa">A爆了</h1>
//等同于
let element=React.createElement(
"h1",
{className:"aaa"},
"A爆了"
)

那么是不是我直接let {type,props,children}=element就可以得到 h1{className:"aaa"}A爆了了呢?我还是太天真了。type确实是h1,但是props打出来是{className: "aaa", children: "A爆了"}。咦?怎么children混在了这里,那么后面得children呢?毫无疑问undefined。也就是说一个React.createElement或者JSX的对象的结构是这样的:

{
type:"h1",
props:{
className:"aaa",
children:"A爆了"
}
}

JSX的花式写法(内含错误演示)

JSX有许多中写法,看的我是眼花缭乱,不如来分析分析这些写法的奥秘,为什么要这么写,然后找一种自己喜欢的方式来写。这里我会以let element=XXX为例子,然后大家可以直接ReactDOM.render(element, document.getElementById('root'));这样渲染。

写法一:一个标签内嵌纯文字

我习惯在写JS的时候,将这些标签写在字符串中,然后拼接起来。看到这么写,真的觉得是个bug,浏览器一定会报错的!然而在react中,不会报错的,这是正确的。

let element=<h1 className="aaa">A爆了</h1>
ReactDOM.render(element, document.getElementById('root'));

错误写法演示:无标签纯文字

那如果是纯文字呢?华丽丽地报错了。说名JSX还是需要标签包裹的。

let element=A爆了

写法二:一个标签嵌套标签混合文字

那么我们多加几个子元素进,也是OK的,没什么毛病。

let element=<h1 className="aaa">aaa<span>A爆了</span>bbbb</h1>

写法三:Fragment包裹所有!

错误写法演示:多个标签并列

如果是很多个并列地兄弟节点呢?突然兴奋!报错了~果然不能皮。为什么呢?大家都是正正经经的HTML标签啊。

let element=
<h1 className="aaa">A爆了</h1>
<h1 className="aaa">A爆</h1>

官方给出的解释是:必须包裹在一个闭合的标签内。意思就是说不能N个闭合标签并列吗?

let element=
<div>
<h1 className="aaa">A爆了</h1>
<h1 className="aaa">A爆</h1>
</div>

外面多加一层div就可以。可是这样可能会多出很多个不需要的div啊,我们干干净净的HTML,会不会变成嵌套地狱啊。官方的求生欲也是很强的,早就想到了这一点,所以有一个官方的组件叫做Fragment。专门用于包裹这些不需要多加一层div的元素们。这个组件的用法:

//首先别忘了导入,不然直接React.Fragment也是可以的
import React,{Fragment} from 'react';
//然后
let element=
<Fragment>
<h1 className="aaa">A爆了</h1>
<h1 className="aaa">A爆</h1>
</Fragment>

前面提到了element打印的结构:{type:"h1",props:{className:"aaa",children:"A爆了"}},好奇心旺盛的我打印了下<Fragment>element是什么样的。结果如下所示,type:Symbol(react.fragment),虽然这个根节点是特殊的标签,不是div,p这种正正经经的HTML标签,但也是一个节点了。也就是说element相当于一个根节点,这个根节点只能有一个,然后这个根节点可以有无数的子节点。

{
type:Symbol(react.fragment),
props:{
children:[
{type: "h1", props: {…}}
{type: "h1", props: {…}}
]
}

写法四:数组真的不行吗?

好奇心旺盛的我,不愿意屈服于所有的外面都要加一个标签包裹,文档说的是一个闭合的标签,那么[]这样包裹一个数组可不可以呢?wow~没有报错!也就是说闭合标签不一定指代<></>也可以是[],来代表一个整体。

let element=
[
<li>1</li>,
<li>1</li>,
<li>1</li>
]

写法五:长的好看而已

我还看到一种写法,就是在最外层加上()来包裹整个节点。我一开始以为这是什么骚操作,会让element变得与众不同。于是,我做了个实验,将两个一样的节点进行对比,不同点在于第一个无(),第二个有(),然后结果是true,也就是说他们本质上没啥不同。所以小伙伴们,不写()也不会报错的。

let element=<div><h1 className="aaa">A爆了</h1><h1 className="aaa">A爆</h1></div>
let element1=(<div><h1 className="aaa">A爆了</h1><h1 className="aaa">A爆</h1></div>)
console.log(JSON.stringify(element1)===JSON.stringify(element))

那么这个括号有什么用呢?当然有!好看!我们来看一样Component里面的render如果没有()会怎么样。

render() {
return (
<div className="App">
<p className="App-intro">To get started, edit<code>src/App.js</code> and save to reload.</p>
</div>
)
}

原本是有()的,然后可以换行,把节点排排整齐。看着也很舒服。然后我们把()去了会怎么样?整齐是整齐,但是会报错啊!

render() {
return
<div className="App">
.....
}

这里就有一个小知识点,js语言设计中return的内容必须一行完成,不要跟回车,不然就会报错。(真是任性的操作)也就是说像下方这么写就没有问题。但是我就没办法保证整整齐齐的标签了啊!这个排版怎么排都丑。所以这个时候()就展现出了他的魅力,代表了一个整体,告诉return我还没结束。所以大家也不要被()给迷惑了,不要怕他。

render() {
return <div className="App">
.....
}

JSX中的标签属性

写JSX会发现,虽然我是在写HTML,但是有些属性好奇怪啊,经常写错,比如最常见的className。我总结出一点我们写标签的时候是HTML,写属性的时候要用JS思维。这样就不复杂,也不难记拉!

\\JS中怎么取class属性的呢?
document.getElementById('myid').className
\\遇到特殊的<label id="label" for="xxx"></label>,这个for在JS中怎么获取呢?
document.getElementById('label').htmlFor

那么问题来了,有一个名为style的属性,你要怎么处理?style就比较复杂了,他不是一个值一个字符串能够搞定搞定的。我先在报错的边缘试探下吧。

试探一:字符串!

let element=<div style="color:green">A爆</div>

报错啦!报错啦!官方提示我们The style prop expects a mapping from style properties to values, not a string. For example, style={{marginRight: spacing + 'em'}} when using JSX.也就是说style需要从样式属性映射到他的值,字符串是不可以的。所以就需要{marginRight: spacing + 'em'}像这样的对象才可以。那为什么要再加一层{}?

试探二:单层{}

let element=<div style={color:"green"}>A爆</div>

直接编译错误了。也就是说JSX中不能直接包含JS的函数。而要用{}包裹起来JS函数。所以才有了双层{}。第一层是代表我是JS,第二层其实就是属性对象本身了。大家不用再试探底线了老老实实:

let element=<div style={{color:"green"}}>A爆</div>

如果想再JSX中加注释怎么办?直接<!--XXX-->肯定报错囧。我们可以用{/*XXX*/}的方式注释,因为{}标签里面是js函数,我们用JS的注释就OK拉!(其实JSX还是JS啊。)

JSX中使用JS

上文提到{}中包含的是JS,那么我们是不是可以玩出更多的花样的?因为{}中我们就可以用JS为所欲为了!

比如循环(正确):

let arr=[1,2,3]
let element=(
{arr.map((v,i)=>
<div>{v}-A爆</div>
)}
)

如果不想循环直接return,可以这样,内部加上大括号,再继续写额外操作。别忘了return,只有=>函数可以省去return

let arr=[1,2,3]
let element=(
<Fragment>
{arr.map((v,i)=>{
if(v===1){
return <span>A爆了</span>
}else{
return <span>B爆了</span>
}
})}
</Fragment>
)

但是如果JS在标签<></>外部的话,就可以直接使用,而不用加上{}

let element=
arr.map((v,i)=>{
if(v==1){
return <div>{v}-A爆</div>
}else{
return <div>{v}-B爆</div>
}
})

大家注意了,这里无论如何element都是一个对象,所以赋予他的值也只能是对象。所以不能直接if/else进行操作,建议再JSX外层操作,而不是直接再JSX中的外层操作。

比如这样,那就只能等吃红牌了。

let element=(
if(v===1){
return <span>A爆了</span>
}else{
return <span>B爆了</span>
}
)

最好是这样:

let v=1;
let element;
if(v===1)
element=<span>A爆了</span>
}else{
element=<span>B爆了</span>
}

在Comopent的render中,我么可以这么写:

render() {
if(v===1){
return <span>A爆了</span>
}else{
return <span>B爆了</span>
}
}

研究完之后,发现JSX就是JS啊,以及每次用JSX“语法”写的元素,都要返回一个数组或者是对象。只要牢记这一点,就可以玩转JSX。

学习React从接受JSX开始的更多相关文章

  1. react学习(一)--JSX简介

    由于在中国银联实习的项目要用到react,所以不得不硬着头皮把react学习一下.这是要往全栈发展吗0.0 正文: 一个最简单的React例子如下, ReactDOM.render( <h1&g ...

  2. 为什么学习React Native三点原因

    React Native不到两岁,兼容Android平台刚刚1年.我学习React Native其实也就不到1年,不算长,也不算短. Paul Graham在文章中写过:大多数人真正注意到你的时候,不 ...

  3. 从0开始学习react(一)

    本人前端小菜鸡一枚,因为公司要重构网站,打算用用react,毕竟一切为了学习(装B)嘛!!! 在学习react之前,看了许多资料,博客,官方文档之类的,可我这记吃不记打的记性,还是需要在这里记录一下, ...

  4. 五分钟学习React(三):纯HTML代码搭建React应用

    上一期我们使用了React官方的脚手架运行React应用.大家可能会觉得这种方法很繁琐,需要配置各种第三方插件.JQuery时代的前端真是让人怀念.这一期,我就带领大家创建一个"怀旧版&qu ...

  5. 五分钟学习React(一): 什么是React

    在前端的世界里,我们要处理的文件不是太多,而是太少.每天开发项目将html.css.js.图片.字体文件都像大杂烩一般加载都网页上.当应用变得越来越臃肿的时候,会发现js用了那么多全局变量,css的继 ...

  6. React学习-React初识

    一.前言 为什么要去学习React呢,关于前端三大框架Angular,Vue,React其实都得去学吧,因为大家都在用啊,大家都再谈论啊,面试什么的都要求,没办法,曾几何时,大家都说求求大佬们别坑新了 ...

  7. 五分钟学习React(六):元素(Element)和组件(Component)

    俗话说"万丈高楼平地起",从这一期开始,我们将使用基于Webpack+Babel的React学习React框架中的一些基础概念.在学习React的过程中经常会把Element.Cl ...

  8. 学习React之前你需要知道的的JavaScript基础知识

    在我的研讨会期间,更多的材料是关于JavaScript而不是React.其中大部分归结为JavaScript ES6以及功能和语法,但也包括三元运算符,语言中的简写版本,此对象,JavaScript内 ...

  9. 新手学习 React 迷惑的点

    网上各种言论说 React 上手比 Vue 难,可能难就难不能深刻理解 JSX,或者对 ES6 的一些特性理解得不够深刻,导致觉得有些点难以理解,然后说 React 比较难上手,还反人类啥的,所以我打 ...

随机推荐

  1. ie7 总结

    1 ie7 对部分属性选择器严重区分大小写 在HTML中,属性名,例如id, title之类是不区分大小写的,CSS中的选择器也应该是如此.但是IE7对属性名是严格区分大小写的! 2 关于属性选择器, ...

  2. 使用Asp.net Identity 创建用户 、登录代码

    1.Identity 1中的注册.登录.注销代码 vs 2013中自带的注册用户代码: 1.首先创建一个ApplicationUser 初始化用户名. 2.使用UserManager创建一个用户,用使 ...

  3. 12_传智播客iOS视频教程_注释和函数的定义和调用

    OC的注释和C语言的注释一模一样.它也分单行注释和多行注释. OC程序里面当然可以定义一个函数.并且定义的方式方法和调用的方式方法和我们C语言是一模一样的.OC有什么好学的?一样还学个什么呢? 重点是 ...

  4. MYSQL自动备份策略的选择(转载)

    原文地址: http://shinepaopao.iteye.com/blog/1938568

  5. 前端性能优化之WebP

    此文已由作者吴维伟授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 前端性能优化是一件很琐碎的事情.它不像其它很多技术,在确切有限的步骤下就可以把功能做好.它就像是在打扫屋子, ...

  6. bzoj 3779: 重组病毒【LCT+线段树维护dfs序】

    %.8lf会WA!!%.8lf会WA!!%.8lf会WA!!要%.10lf!! 和4817有点像,但是更复杂. 首先对于操作一"在编号为x的计算机中植入病毒的一个新变种,在植入一个新变种时, ...

  7. P4055 [JSOI2009]游戏

    传送门 把这个图给黑白染色然后建二分图,如果有完备匹配那么就gg,否则放在所有的非匹配点都可以 简单来说的话就是放在非匹配点,那么对手的下一步必定移到一个匹配点,然后自己可以把它移到这个匹配点所匹配的 ...

  8. P5107 能量采集

    传送门 官方题解 话说最后的答案忘记取模了结果连暴力都挂了可海星-- //minamoto #include<bits/stdc++.h> #define R register #defi ...

  9. Spring Boot之配置文件值注入(@ConfigurationProperties)

    前言:Spring Boot配置文件值的注入有两种方式,分别是 @ConfigurationProperties @Value 这里我们使用第一种 首先我们创建一个application.yml文件, ...

  10. (博弈论 高精度小数)51NOD 1185 威佐夫游戏 V2

    有2堆石子.A B两个人轮流拿,A先拿.每次可以从一堆中取任意个或从2堆中取相同数量的石子,但不可不取.拿到最后1颗石子的人获胜.假设A B都非常聪明,拿石子的过程中不会出现失误.给出2堆石子的数量, ...