一、什么是JSX
- JSX是由Facebook公司起草的JS扩展语法。
- JSX会被babel编译,最终会被转化成React.createElement,所以JSX本质上是一个JS对象(React对象)。
二、JSX特点
- 每个JSX表达式有且仅有一个根节点。
- JSX语法会被编译成React.createElement的形式,如果有多个根节点则无法进行编译。如果jsx表达式有多个子元素,那么必须要添加一个根节点,此时有两种添加方式。
- 在可以改变页面结构的情况下,根标签可以为
<div></div>
。
- 不改变页面结构,根标签为
<React.Fragment></React.Fragment>
,既空标签<></>
。
- 每个jsx表达式子元素必须结束(XML规范)。
let img = (
<>
<img src='xxx'>{/*报错*/}
{/*两种结束方式*/}
<img src='xxx'></img>
<img src='xxx'/>
</>
)
三、在JSX中嵌入表达式
- 在JSX中使用注释:
{/*注释内容*/}
。
- 将表达式作为内容的一部分。
const a = 123,b=234,c='Aziel';
const div = (
<div>
{a}*{b} = {a*b}
{c}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
//表达式部分编译之后是模板字符串
//React.createElement('div',{},`${a}*${b} = ${a*b}`)
- 表达式为true、false、undefined、null,页面不会显示任何内容。
const div = (
<div>
{null}
{undefined}
{false}
{true}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
//表达式为普通对象会报错
const obj = {
name:'Aziel'
}
let div = (
<div>
{obj}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
//表达式为react对象会正常显示
const obj = <span>这是一个react元素对象</span>
let div = (
<div>
{obj}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
- 表达式为数组,程序运行时会遍历数组并将每个数组元素作为子元素加到JSX中。如果数组元素是react对象,则需要加key值。
//数组元素为非react对象
const arr = [1,2,3,4,5];
const div = (
<div>
{arr}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
//数组元素为react对象
const numbers = new Array(30);
// fill(固定值):将固定值替换成数组元素。
numbers.fill(0);
// map(func):遍历数组,用回调函数处理数组的每一项,将返回结果放入新的数组。
let lis = numbers.map((item,i)=>{return <li key={i}>{i}</li>});
const div = (
<div>
{lis}
</div>
)
ReactDOM.render(div, document.getElementById('root'));
- 表达式为元素属性值。
- JSX语法中属性使用小驼峰命名法。
- 类样式:className,不能用class。
- 行间样式:style属性值不能为字符串,后面应为表达式,内部是一个对象
const url = 'XXX'
const cls = 'image'
const div = (
<div>
<img src = {url} className={cls} style={{marginLeft:"50px",width:"200px"}}/>
</div>
)
- 防止注入攻击。
- 即使表达式内容是恶意脚本,ReactDOM也不会将该脚本的html元素作为页面结构。
//页面显示<h1>afasfasfd</h1><p>阿斯顿法定发送</p>
const content = "<h1>afasfasfd</h1><p>阿斯顿法定发送</p>";
const div = (
<div>
{content}
</div>
);
ReactDOM.render(div, document.getElementById("root"));
- 如果我们一定要让脚本的html元素作为页面结构放入页面上,我们怎么做?
//React之所以设置了重重障碍来解决该问题,目的就是提醒我们这么做很危险。
//该方法这么恶心,你还去用它,就说明你真有这个需求!
const content = "<h1>afasfasfd</h1><p>阿斯顿法定发送</p>";
const div = (
<div dangerouslySetInnerHTML={{
__html: content
}}>
</div>
);
ReactDOM.render(div, document.getElementById("root"));
四、元素不可变性
- 虽然JSX是一个React对象,但是该对象的所有属性都不可更改,实际上用了Object.freeze(根标签)将JSX给冻结了,既该对象是只读的。
- 如果确实要更改元素属性应该怎么办?只有一种办法,那就是重新创建JSX。
- 可以用循环或定时器不断创建新的JSX对象,并用React.render将新创建的JSX对象渲染到页面上,这就实现了对JSX对象的某个属性动态改变的效果。
- 这和电影的原理有点相似,电影的每一帧都是静态的,当电影的每一帧依次快速的渲染到页面上的时候,电影就动了。
- 程序不断的创建新的JSX元素,这样做效率是不是很低?
- 答案是效率一点都不低。
- 实际上每一时刻创建的JSX元素它不是dom元素,本质上就是普普通通的对象,创建普通对象的开销非常小。
- ReactDOM.render将JSX映射成dom元素,并不断的将dom元素渲染到页面上效率很低?
- 答案是效率一点都不低。
- React对该问题进行了优化,页面上已经渲染的dom元素不会被删除,每次渲染时,被修改的仅仅是元素的内容部分而已。
let num = 0;
setInterval(() => {
num++;
const div = (
<div title="asdfadf">
{num}
</div>
);
ReactDOM.render(div, document.getElementById("root"));
}, 1000);