分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > IT知识

深入 JSX

发布时间:2023-09-06 01:55责任编辑:蔡小小关键词:暂无标签

从本质上讲,JSX 只是为React.createElement(component, props, ...children)函数提供的语法糖。JSX代码:

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

编译后的结果为:

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

如果不存在子节点,你可以使用自闭合(self-closing)格式的标签。例如:

1
<div className="sidebar"/>

编译为:

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

可以发现对于非自定义的html标签‘div’是以字符串的形式传入的。

在线 Babel 编译器

指定 React 元素类型

一个 JSX 标签的开始部分决定了 React 元素的类型。

首字母大写的标签指示 JSX 标签是一个 React 组件。这些标签会被编译成 命名变量 的直接引用。所以如果你使用 JSX<Foo />表达式,那么Foo必须在作用域中。

React 必须在作用域中

因为 JSX 被编译为React.createElement的调用,所以React库必须在你 JSX 代码的作用域中。

例如,所有的 imports 在这段代码中都是必须的,虽然ReactCustomButton并有直接从 JavaScript 中引用:

1
2
3
4
5
6
7
import React from‘react‘;
import CustomButton from‘./CustomButton‘;
functionWarningButton() {
// return React.createElement(CustomButton, {color: ‘red‘}, null);
return<CustomButton color="red"/>;
}

如果你不使用 JavaScript 打包器,而是通过在<script>标签加载 React ,它已经作为一个全局React存在。

对 JSX 类型使用点语法

在 JSX 中,你也可以使用点语法引用一个 React 组件。如果你有一个单一模块(module) ,但却 导出(exports) 多个 React 组件时,这将会很方便。例如,如果MyComponents.DatePicker是一个组件,你可以直接在 JSX 中使用它:

1
2
3
4
5
6
7
8
9
10
11
import React from‘react‘;
const MyComponents = {
DatePicker:functionDatePicker(props) {
return<div>Imagine a {props.color} datepicker here.</div>;
}
}
functionBlueDatePicker() {
return<MyComponents.DatePicker color="blue"/>;
}

通过点语法,可以将具有相同类型的组件封装在一个地方,方便管理。

用户定义组件必须以大写字母开头

当一个元素类型以小写字母开头,它表示引用一个类似于<div>或者<span>的内置组件,会给React.createElement方法传递‘div‘或者‘span‘字符串。以大写字母开头的类型,类似于<Foo />,会被编译成React.createElement(Foo),对应于自定义组件 或者在 JavaScript 文件中导入的组件。

在运行时选择类型

不能使用一个普通的表达式作为 React 元素类型。如果你想使用普通表达式来表示元素类型,首先你需要将其赋值给大写的变量。这通常会出现在根据不同的 props 渲染不同的组件时:

1
2
3
4
5
6
7
8
9
10
11
12
import React from‘react‘;
import { PhotoStory, VideoStory } from‘./stories‘;
const components = {
photo: PhotoStory,
video: VideoStory
};
functionStory(props) {
// 错误!JSX 类型不能是表达式
return<components[props.storyType] story={props.story} />;
}


为了解决这个问题,首先需要将表达式赋值给一个以大写字母开头的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
import React from‘react‘;
import { PhotoStory, VideoStory } from‘./stories‘;
const components = {
photo: PhotoStory,
video: VideoStory
};
functionStory(props) {
// 正确!JSX 类型可以是一个以大写字母开头的变量.
const SpecificStory = components[props.storyType];
return<SpecificStory story={props.story} />;
}

JSX 中的 props(属性)

有几种不同的方式来指定 JSX 中的 props(属性) 。

JavaScript 表达式作为 props(属性)

常用方法:

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

对于MyComponent来讲,props.foo的值为10,因为表达式1 + 2 + 3 + 4会被计算估值。

在 JavaScript 中,if语句和for循环不是表达式,因此不能在 JSX 中直接使用。但你可以将他们放在附近的代码块中,例如:

1
2
3
4
5
6
7
8
9
functionNumberDescriber(props) {
let description;
if(props.number % 2 == 0) {
description = <strong>even</strong>;
}else{
description = <i>odd</i>;
}
return<div>{props.number} is an {description} number</div>;
}

字符串字面量

props(属性) 默认为 “true”

如果你没给 prop(属性) 传值,那么他默认为true。下面两个 JSX 表达式是等价的:

1
2
3
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />

通常情况下,不建议使用这种类型,因为这会与ES6中的对象shorthand混淆。ES6 shorthand 中{foo}指的是{foo: foo}的简写,而不是{foo: true}。这种行为只是为了与 HTML 的行为相匹配。(愚人码头注:举个例子,在 HTML 中,<input type="radio" value="1" disabled /><input type="radio" value="1" disabled="true" />是等价的。JSX 中的这种行为就是为了匹配 HTML 的行为。)

属性扩展

如果你已经有一个 object 类型的props,并且希望在 JSX 中传入,你可以使用扩展操作符...传入整个 props 对象。这两个组件是等效的:

1
2
3
4
5
6
7
8
functionApp1() {
return<Greeting firstName="Ben"lastName="Hector"/>;
}
functionApp2() {
const props = {firstName:‘Ben‘, lastName:‘Hector‘};
return<Greeting {...props} />;
}


JSX Children

通过使用{}包裹,你可以将任何的 JavaScript 元素而作为 children(子元素) 传递,下面表达式是等价的:

1
2
3
<MyComponent>foo</MyComponent>
<MyComponent>{‘foo‘}</MyComponent>

Functions(函数) 作为 Children(子元素)

通常情况下,嵌入到 JSX 中的 JavaScript 表达式会被认为是一个字符串、React元素 或者是这些内容的一个列表。然而,props.children类似于其他的 props(属性) ,可以被传入任何数据,而不是仅仅只是 React 可以渲染的数据。例如,如果有自定义组件,其props.children的值可以是回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Calls the children callback numTimes to produce a repeated component
functionRepeat(props) {
let items = [];
for(let i = 0; i < props.numTimes; i++) {
items.push(props.children(i));
}
return<div>{items}</div>;
}
functionListOfTenThings() {
return(
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index}inthe list</div>}
</Repeat>
);
}

这个例子中,直接在Repeat组件中传了一个钩子函数进去,并且用一对{}包裹起来,在Repeat中,就可以通过props.children拿到父组件中钩子函数的返回值,并且通过加工包装成React元素。

传递到自定义组件的 children(子元素) 可以是任何内容,只要在渲染之前组件可以将其转化为 React 能够处理的东西即可。

Booleans, Null, 和 Undefined 被忽略

falsenullundefined,和true都是有效的的 children(子元素) 。但是并不会被渲染,下面的JSX表达式渲染效果是相同的:

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>

在有条件性渲染 React 元素时非常有用。如果showHeadertrue时,<Header />会被渲染:

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

短路表达式:

showHeader为true则往下执行,为false则中断,<Header>组件将不会被渲染。

需要注意的是“falsy”值,例如数值0,仍然会被 React 渲染。例如,这段代码不会按照你预期的发生,因为当props.messages是一个空数组时0会被打印:

1
2
3
4
5
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>

要修复这个问题,确保&&之前的表达式总是布尔值:

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved