一、前言
前一章我们搭建了Reactjs的标准工程,本章节我们基于标准工程的demo应用,了解react的 渲染和JSX语法。
二、渲染
1、在标准工程的public/index.html下
<div id="root"></div>
该div是我们整个应用的根节点,所有的DOM节点都挂载在该节点下,可以看成web容器。
2、再看src/index.js代码
//1、引入相关包
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
//2、将app定义节点挂载到root节点下
ReactDOM.render(<App />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
(1)、引入相关的组件和包,其中"react","react-dom"是react的基本包,App是应用节点组件。
(2)、ReactDOM.render将App定义的节点挂载到root节点下,root下的所有节点都在React的作用域中。可以类比Vue的入口方法new Vue()。
3、继续看src/App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
定义App方法然后导出,App方法返回一段类似html的代码段,该代码段最终渲染成如下dom节点
我们看相似度达到99%,DOM结构以及标签相同,但是也有不同的地方
(1)class属性名,在代码段中为className,
(2)img的src的为引用的表达式。
这就是我们接下来要隆重介绍的JSX。
三、什么是JSX
熟悉Vue的同学知道(后面我们会经常与vue比较,理解两者的异同点),UI和JS是分开的,UI采用的Template模式,对于使用原生态前端的同学更容易掌握。在Reactjs中,一般采用将UI嵌套在js表达式中,即JSX(Javascript XML),虽然从形式上看类似HTML,但是实质上是javascript表达式,是javascript的一种扩展形式。有以下特点:
1、引用表达式
既然JSX是js表达式,那当然可以引用表达式了,比如demo中的img的src的属性值就是使用了表达式,需要注意的是表达式放置在{}中。
可以使用对象表达式,如下面的user
...
const user = {
firstName: 'ma',
lastName: 'jack'
};
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
hello,{user.firstName},
Edit <code>src/App.js</code> and save to reload.
</p>
...
</header>
</div>
);
}
export default App;
也可以使用函数表达式,如下面的formatName
...
const user = {
firstName: 'ma',
lastName: 'jack'
};
function formatName(user){
return user.lastName+" "+user.firstName;
}
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
hello,{formatName(user)},
Edit <code>src/App.js</code> and save to reload.
</p>
....
</header>
</div>
);
}
还可以支持三元表达式,但不支持if else,for的条件表达式。
<div>
<h1>{i == 1 ? 'True!' : 'False'}</h1>
</div>
2、样式
(1)采用className标签设置样式,如demo中,在App.css中定义样式,将文件导入到App.js中,使用className属性调用
(2)内联样式,如下面的style
...
const style={
fontSize: 100,
color: '#FF0000'
}
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p style ={style}>
Edit <code>src/App.js</code> and save to reload.
</p>
...
</header>
</div>
);
}
这里样式属性的key值需要使用驼峰命名方式,而不是css的短连接模式。本质上,JSX的内联样式使用的字面量对象,而不是字符串,也可以这样写:
<p style ={{fontSize: 100, color: '#FF0000'}}>
实际上,除了样式,Reactjs在JSX中实现了一套完整的DOM表达方式,所有的特性和属性都是采用小驼峰命名方式。
四、为什么要用JSX
如果初学JSX,特别之前使用html,js原生态写前端的同学,非常不习惯将UI与JS糅合在一起的写法。那么为什么Reactjs推荐使用,按照官方说法,总结起来:
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
- 它是类型安全的,在编译过程中就能发现错误。
- 使用 JSX 编写模板更加简单快速。
第三点,有点王婆卖瓜,自卖自夸的意思,只能说仁者见仁,智者见智。我们重点看下前两点。
1、JSX执行更快
我们先来看下JSX的编译过程,官网上给了一个如下的例子。
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
Babel会把 JSX 转译成一个名为 React.createElement()
函数调用
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
createElement实际上创建一个如下的树型结构,称之为"React元素"
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
了解Vue的同学应该很快知道,这就是Vue中所说的Vnode(VUE源码学习第九篇--编译(generate)),他们的原理都是相似的,通过这种React元素,最终构建VDOM,以保持随时更新。
在VUE源码学习第七篇--编译(parse),我们梳理了vue的编译过程:
通过正则匹配对Template进行解析,最终生成render表达式,这个过程是非常耗时的,而JSX本来就是JS,无需这一步,大大提高了编译效率。
2、安全性
这里主要是说的是XSS(Cross Site Script,跨站脚本攻击),它指的是恶意攻击者往Web页面里插入恶意脚本代码,而程序对于用户输入内容未过滤,当用户浏览该页之时,嵌入其中Web里面的脚本代码会被执行,从而达到恶意攻击用户的特殊目的。
比如以下面一段
const username = "jack ma";
....
<h1>{username}</h1>
username可以是从某个地方获取的(如input),这里为了简化,直接写死来演示。
有人故意篡改了内容
const username = "<img onerror='alert(\"hi!\")' src='invalid-image' />";
当我们运行应用,此时页面正常显示了这段文字,并没有弹出"hi"。
这是应该Reactjs将所有的内容在渲染之前都被转换成了字符串,这样就有效的防止了XSS。
有同学说,我就是希望转义成html,打印hi,怎么办,可以使用dangerouslySetInnerHTML(类似原生的innerHtml)。
const username = "<img onerror='alert(\"hi!\")' src='invalid-image' />'}";
...
<h1 ><div dangerouslySetInnerHTML = {{"__html":username}} /></h1>
五、总结
本章节点主要阐述了渲染以及JSX,重点对JSX的语法,以及使用JSX的优势进行了详细介绍。
JSX虽然形式上类似html语法,但实际上是javascript的表达式,是javascript的扩展形式。
JSX的优点在于编译快,安全性高,以及编写速度快。