JSX In Depth
文章目录

JSX In Depth

JSX将通过Babel进行编译.

标准首位标签格式

1
2
3
<MyButton color="blue" shadowSize={2}>
Click Me
</MyButton>

compiles into:

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

自闭合标签格式

You can also use the self-closing form of the tag if there are no children. So:

1
<div className="sidebar" />

compiles into:

1
2
3
4
5
React.createElement(
'div',
{className: 'sidebar'},
null
)

Specifying The React Element Type

一般Component使用大写字母开头, 如果在当前JSX里面使用 <XXX/> 那么XXX这个Component就必须出现在Scope之内.

另外可以使用 import 语句将Component引用到Scope内

Using Dot Notation for JSX Type

1
2
3
4
5
6
7
8
9
10
11
12
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" />;
}

User-Defined Components Must Be Capitalized

自定义Component(比如 <MyComponent/> )应该大写字母开头
系统自带的Component(比如 <div/> )应该小写字母开头

否则系统会抛出警告

Choosing the Type at Runtime

注意JSX Obj的tags必须是完整的单词, 如果想要动态生成tag名称可以用赋值的办法

错误的例子:

1
2
3
4
function Story(props) {
// Wrong! JSX type can't be an expression.
return <components[props.storyType] story={props.story} />;
}

正确的做法:

1
2
3
4
5
function Story(props) {
// Correct! JSX type can be a capitalized variable.
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />;
}

Prop in JSX

JavaScript Expressions as Props

关于使用JS表达式作为prop:

1
<MyComponent foo={1 + 2 + 3 + 4} />

If condition within JSX

不能够直接使用, 但是可以用这个替代方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function NumberDescriber(props) {
let description;

// check the condition
if (props.number % 2 == 0) {
description = <strong>even</strong>;
} else {
description = <i>odd</i>;
}


return <div>{props.number} is an {description} number</div>;


}

另外一个很实用的条件判断的snippet

This can be useful to conditionally render React elements. This JSX only renders a <Header /> if showHeader is true :

1
2
3
4
<div>
{showHeader && <Header />}
<Content />
</div>

String Literals

When you pass a string literal, its value is HTML-unescaped. So these two JSX expressions are equivalent:

1
2
3
<MyComponent message="<3" />

<MyComponent message={'<3'} />

Props Default to “True”

If you pass no value for a prop, it defaults to true. These two JSX expressions are equivalent:

1
2
3
<MyTextBox autocomplete />

<MyTextBox autocomplete={true} />

Spread Attributes

If you already have props as an object, and you want to pass it in JSX, you can use ... as a “spread” operator to pass the whole props object. These two components are equivalent:

提供Props时, 若有一个Obj并且这个Obj里面所有Attr和需要的Prop相匹配, 那么可以使用 spread operator 进行赋值

1
2
3
4
5
6
7
8
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}

function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}

另外对于 spread operator也可以给部分值赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const Button = props => {

//将传进函数里面的props.kind 赋值给kind, 将其他属性赋值给...other
const { kind, ...other } = props;

const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
//然后将...other传给button这个elem, 而没有传递kind这个参数
return <button className={className} {...other} />;
};

const App = () => {
return (
<div>
<Button kind="primary" onClick={() => console.log("clicked!")}>
Hello World!
</Button>
</div>
);
};

关于解构运算符

MDN参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator

这玩意是ES6新引进的运算符, 通过三个点进行引用 ...

1
2
3
4
5
6
7
8
9
10
11
12
13
function sum(x,y,z){
return x+y+z
}
console.log(sum(...[1,2,3])) //6
console.log(sum(...[1,2,3,4,5])) //6
console.log(sum(...[1,,3,4,5])) //NaN
var doSomething = function(...args){
return sum(..args)
}
console.log(doSomething(...[1,2,3])) //6
//对Object是否有效呢?
var obj = { a:"A", b:"B", c:"C", d:"D", e:"E" }
var {a,b,...others} = obj //报错var {a,b,...others} = obj //报错

在老版本ES6中, 对Obj进行解构赋值会报错, 但是JSX中允许这样的使用.

Children in JSX

子元素全部会通过 props.children 进行引用.

另外如果没有子tag而只是放置了一段文本, 那么props.children就会是tag之间的一段字符串

Hint: HTML is unescaped!

1
2
3
<MyComponent>Hello world!</MyComponent>

<div>This is valid HTML & JSX at the same time.</div>

tags之间的空格和空行都会被忽略.

1
2
3
4
<div>

Hello World
</div>

另外也可以将JS表达式用于child elem. 比如一个很典型的使用数组循环生成列表的例子:

1
2
3
4
5
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);

Functions as Children

反正只要最后返回的是一个完整的JSX Obj即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

// 2. 我们在渲染parent elem
function Repeat(props) {
let items = [];
for (let i = 0; i < props.numTimes; i++) {
// 3. 通过调用child elem对应的函数生成jsx obj
items.push(props.children(i));
}
return <div>{items}</div>;
}

// 1. 返回的JSX obj的child elem是个函数
function ListOfTenThings() {
return (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
}

Booleans, Null, and Undefined Are Ignored

false , null , undefined , and true are valid children. They simply don’t render. These JSX expressions will all render to the same thing:

1
2
3
4
5
6
7
8
9
10
11
<div />

<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>