JSX

JSX

Follow me on GitHub

  • JSX
    • 1. 为什么会有JSX?
    • 2. JSX的基本使用
      • 2.1 JSX中可直接包含Javascript表达式
      • 2.2 JSX本身也是表达式
      • 2.3 使用JSX中指定属性
      • 2.4 使用JSX指定Children
      • 2.5 JSX可以阻止注入式攻击
    • 3. JSX进阶
      • 3.1 JSX的编译
      • 3.2 指定React Element类型
      • 3.3 JSX中的prop
      • 3.4 JSX中的Children

JSX是对Javascript的语法扩展,而不是一种模板语言。JSX不是字符串,也不是HTML。

1. 为什么会有JSX?

React认为渲染逻辑跟UI逻辑(事件如何处理,状态如何改变,数据如何展示)实际上天然相关的。
React并没有使用传统的将表现(markup)与逻辑(javascript)分离的方式,而是使用松耦合的组件将表现和逻辑组合到了一起。
JSX实际上是组件渲染的语法糖,其糅合了标记语言与UI对应的优点,同时可以直接处理Javascript代码。

ps:表现与处理逻辑分离仍旧有很大意义,Presentation Component与Container Component的提出正式这一原则的应用。
在逻辑复杂的系统中,将状态抽取到Redux中进行统一管理,将处理逻辑抽取到Container Component中,将UI展示抽取到Presentation Component中。
实现了数据模型处理逻辑数据展示的分离。

2. JSX的基本使用

2.1 JSX中可直接包含Javascript表达式

JSX将Javascript表达式包裹在大括号{}中使用。

function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  

Hello, {formatName(user)}!

); ReactDOM.render( element, document.getElementById('root') );

2.2 JSX本身也是表达式

JSX在编译后实际上是Javascript对象,因此可以直接在if或者for循环中使用,也可以赋值给变量,或者作为函数参数传递,也可以作为函数返回值。

function getGreeting(user) {
  if (user) {
    return 

Hello, {formatName(user)}!

; } return

Hello, Stranger.

; }

2.3 使用JSX中指定属性

可以使用双引号指定字符串字面量

const element = 
;

也可以使用大括号指定Javascript表达式

const element = ;

注意:JSX中的属性使用camelCase(与HTML不同)

2.4 使用JSX指定Children

const element = (
  

Hello!

Good to see you here.

);

2.5 JSX可以阻止注入式攻击

React DOM默认在渲染前对JSX中的值进行转义,这样就避免了使用应用中未显式指定的值就行注入式攻击,可以帮助防范XSS攻击。

3. JSX进阶

3.1 JSX的编译

JSX提供了React.createElement(component,props,...children)函数的语法糖。


  Click Me

会编译成

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

会编译成

React.createElement(
  'div',
  {className: 'sidebar'},
  null
)

3.2 指定React Element类型

JSX标签决定了React Element的类型,如果首字符是大写,那么代表是React Component,如果首字符是小写,那么是HTML DOM。

  • React以及组件必须在作用域中

如果是React Component,那么标签的名称就代表着保存React组件实例变量的名称,因此此变量必须在当前作用域中。
同时,JSX编译后也要使用到React变量,因此React变量也要保证在当前作用域中。

PS: 使用函数组件的时候,会忘记导入React模块,此时就会出现错误提示(React is undefined),其实就是因为模块中未导入React。

import React from 'react';
import CustomButton from './CustomButton';

// React与CustomButton都需要在作用域中
function WarningButton() {
  // return React.createElement(CustomButton, {color: 'red'}, null);
  return ;
}
  • 可使用点标识符

如下面的MyComponents.DatePicker

import React from 'react';

const MyComponents = {
  DatePicker: function DatePicker(props) {
    return 
Imagine a {props.color} datepicker here.
; } } function BlueDatePicker() { return ; }
  • 用户自定义组件首字母需大写

自定义组件的首字母需大写,HTML支持的tag名称都已经作为React内置的组件,需小写。

import React from 'react';

// Correct! This is a component and should be capitalized:
function Hello(props) {
  // Correct! This use of 
is legitimate because div is a valid HTML tag: return
Hello {props.toWhat}
; } function HelloWorld() { // Correct! React knows is a component because it's capitalized. return ; }
  • 运行时动态选择组件类型

如果需要动态选择组件类型,那么将组件保存在常量中(首字母大写),然后在JSX标签中可使用此变量名。

import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // Correct! JSX type can be a capitalized variable.
  const SpecificStory = components[props.storyType];
  return ;
}

3.3 JSX中的prop

在JSX中有一下几种方式指定props

  • 字符串字面量

使用引号包裹表示字符串字面量,所以下面两种方式是等同的。




当使用字符串字面量的时候,其值会进行HTML解析,所以下面两个JSX表达式是等同的。




  • Javascript表达式

使用大括号包裹


  • 默认为'True'

如果prop不指定值,那么其值默认为true(其表现跟HTML的disabled,checked,readOnly属性类似)




  • 延展属性

如果已经有props对象,可使用ES6的扩展运算符...传递整个props对象。以下两种方式等同

function App1() {
  return ;
}

function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return ;
}

...运算符也可以用来对props对象进行分割,例如下面代码提取kind,将其他属性放入新的对象other

const Button = props => {
  const { kind, ...other } = props;
  const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
  return 
    
); };

延展属性会传递不必要的props给组件(或者是无效的HTML属性给DOM),所以,不要滥用

3.4 JSX中的Children

JSX表达式包含一个打开标签和一个关闭标签,在这两个标签之前的内容会作为一个特殊属性传递props.children
有以下几种方式可以传递children:

  • 字符串字面量

props.children就是字符串字面量"Hello World!"

Hello world!

HTML会被解析,所以转义字符在JSX中跟HTML中使用方式一样

This is valid HTML & JSX at the same time.

JSX会移除行首和行尾的空白字符,也会移除空白行,临近标签的空白行也会移除,字符串中的换行会被作为一个空格处理。
以下几种方式是相同的

Hello World
Hello World
Hello World
Hello World

想用JSX表示多个空格,需要使用 

  • JSX表达式作为Children

可使用JSX元素作为Children,便于组件嵌套


  
  

可以嵌套不同类型的children(like HTML)

Here is a list:
  • Item 1
  • Item 2

React组件可以返回元素数组(不强制使用元素进行包裹)

render() {
  // No need to wrap list items in an extra element!
  return [
    // Don't forget the keys :)
    
  • First item
  • ,
  • Second item
  • ,
  • Third item
  • , ]; }
    • Javascript表达式作为Children

    可使用大括号{}直接包裹表达式作为children

    function Item(props) {
      return 
  • {props.message}
  • ; } function TodoList() { const todos = ['finish doc', 'submit pr', 'nag dan to review']; return (
      {todos.map((message) => )}
    ); }

    也可以跟其他类型混合使用

    function Hello(props) {
      return 
    Hello {props.addressee}!
    ; }
    • 函数作为Children

    props.children可以传递任何类型的数据,例如函数,在React渲染之前将其
    转换为React可以识别的对象(字符串,React元素,及其数组)即可。

    如下面ListOfTenThings传递给Repeat组件的props.children是一个函数,但是在Repeat组件渲染前,将其转换
    为了React元素数组items

    // Calls the children callback numTimes to produce a repeated component
    function Repeat(props) {
      let items = [];
      for (let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
      }
      return 
    {items}
    ; } function ListOfTenThings() { return ( {(index) =>
    This is item {index} in the list
    }
    ); }
    • Boolean,Null,Undefined都将被忽略

    false,true,null,undefined都是有效的children,但是都不渲染,以下几种方式相同

    {false}
    {null}
    {undefined}
    {true}

    因此,可以使用&运算符进行条件渲染

    {showHeader &&
    }

    需要注意的是一些falsy value,例如0仍旧会被渲染。如果要作为渲染条件使用,请将其转换为Boolean.

    此外,如果需要渲染false,null,true,undefined这些值,可将其转换为字符串

    你可能感兴趣的:(JSX)