JSX
const element = <h1>Hello, world!</h1>;
这个有趣的标签语法既不是字符串也不是 HTML。它被称为 JSX,是一个 JavaScript 的语法扩展。
在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后得到 JavaScript 对象。
Babel编译后的JSX
阅读上面的代码,我们发现JSX的语法、结构(允许嵌套)和HTML很相似、但JSX本质上更接近于JavaScript,Babel会把 JSX 转译成一个名为 React.createElement() 函数调用
以下两种代码完全等效
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
React.createElement() 会预先执行一些检查,以帮助你编写无错代码,但实际上它创建了一个这样的对象:
// 注意:这是简化过的结构
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
所以JSX语法实质上为Babel将JSX翻译为一个React.createElement()函数, 而这个函数返回一个Element对象, Element是一个对象树,React拿到这个对象树再转换为真实DOM渲染到浏览器界面上。
Babel对JSX的三种翻译
我们知道JSX中有标签、字符串、大括号表达式三种内容,那翻译后是什么样子呢
function App() {
return (
<div className="App" title='app'>
<h2> Hello, React </h2> //标签
this is JSX //字符串
{
2>1? <b>yes</b>:<b>no</b> //表达式
}
</div>
);
}
下面是Babel翻译后的JavaScript
"use strict";
function App() {
return React.createElement(
"div",
{
className: "App",
title: "app"
},
React.createElement("h2", null, " Hello, React "), //标签
"this is JSX", //字符串
2 > 1 ? React.createElement("b", null, "yes") : React.createElement("b", null, "no")); //大括号表达式
}
JSX 防止注入攻击
React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS(cross-site-scripting, 跨站脚本)攻击。
深入JSX
在 JSX 类型中使用点语法
在 JSX 中,你也可以使用点语法来引用一个 React 组件。当你在一个模块中导出许多 React 组件时,这会非常方便。例如,如果 MyComponents.DatePicker 是一个组件,你可以在 JSX 中直接使用:
import React from 'react';
const MyComponents = {
DatePicker: function DatePicker(props) {
return <div>Imagine a {props.color} datepicker here.</div>;
}
}
function BlueDatePicker() {
return <MyComponents.DatePicker color="blue" />;}
用户定义的组件必须以大写字母开头
React认为:以小写字母开头的元素是一个HTML元素,如<div></div>会将字符串'div'传递给React.createElement('div'),而大小字母开头的元素则是一个React组件,如<Hello></Hello>会将Hello组件对象传递给React.createElement(Hello),正是由于这个差异,我们在定义组件的时候应该以大写字母开头
Babel翻译HTML元素和React组件的差别
在运行时选择组件类型
组件的类型可以在运行时动态决定
function Eat(){
return (<div>Eat</div>)
}
function Sleep() {
return ( <div>Sleep</div>)
}
function Show(props){
return (<props.component></props.component>)
}
function App() {
return (<Show component = {Sleep} > </Show>)
}
JSX 中的子元素
包含在开始和结束标签之间的 JSX 表达式内容将作为特定属性 props.children 传递给外层组件。有几种不同的方法来传递子元素:
字符串字面量
<MyComponent>Hello world!</MyComponent>
props.children = 'Hello world!'
JSX 子元素
子元素允许由多个 JSX 元素组成。这对于嵌套组件非常有用:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
JavaScript 表达式作为子元素
function Item(props) {
return <li>{props.message}</li>; //JavaScript 表达式作为子元素
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)} </ul>
);
}
函数作为子元素
props.children 和其他 prop 一样,它可以传递任意类型的数据,而不仅仅是 React 已知的可渲染类型。但这种做法并不常见
布尔类型、Null 以及 Undefined 将会忽略
这一点在实现依据条件进行渲染的时候很有效,例如,下面JSX仅当showHeader为true时才被渲染。 如果我们想要渲染布尔类型、Null 以及 Undefined这些值,需要先转为String,再渲染
<div>
{showHeader && <Header />} <Content />
</div>