【学习记录】React之JSX简介

174 阅读3分钟

JSX

const element = <h1>Hello, world!</h1>;

这个有趣的标签语法既不是字符串也不是 HTML。它被称为 JSX,是一个 JavaScript 的语法扩展。

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

Babel编译后的JSX

image.png

阅读上面的代码,我们发现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组件的差别

image.png

在运行时选择组件类型

组件的类型可以在运行时动态决定

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>