React:JSX进阶

本文详细探讨了JSX的使用,包括指定React元素类型、JSX中的props、子元素等方面。强调了React组件首字母需大写、如何在JSX中使用点运算符引用组件、以及如何处理不同类型的props和子元素。此外,还介绍了如何在运行时选择类型以及如何处理Boolean, Null和Undefined值的情况。" 123700184,9053557,Ubuntu20编译安装DCMTK3.6.6教程,"['Linux', 'Ubuntu', '软件安装', 'DCMTK', '医学影像处理']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JSX In Depth

最根本上,JSX仅仅提供React.createElement(component,props, ...children)函数这样的语法糖,JSX代码:

//JSX代码
<MyButton color="blue" shadowSize={2}>
    Click Me
</MyButton>
//编译之后的JavaScript代码
React.createElement(
    MyButton,
    { color:"blue", shadowSize:2 },
    "Click Me"
)
//自封闭式标签风格来描述没有子元素的元素
<div className="sidebar" />
//可以编译成JavaScript代码
React.createElement(
    'div',
    { className: 'sidebar' },
    null
)

指定React元素类型

JSX标签的第一个部分指定了React元素的类型,首字母大写的标签说明了它是一个引用的React组件,这些标签会被编译称为一个命名属性的直接引用,所以如果需要使用JSX<Foo />标签,那么Foo必须要在作用域内被定义。

React必须在定义域内

如果JSX编译器调用了React.createElement,那么React库必须一直在你的JSX代码中,比如:

//下面的两个引用对于这段代码都是必须的,React和CustomButton都不是直接引用
import React from 'react';
import CustomButton from './CustomButton';

function WarningButton() {
    return <CustomButton color="red" />
}

如果不使用打包工具,并且将React添加到script标签内,那么React就已经是一个全局变量了。

在JSX类型中使用点运算符

也可以在JSX中使用点运算符来引用一个React组件,当从一个模块中导出了许多React组件的时候,这样的使用方法非常方便,比如:

import React from 'react';
//MyComponents.DatePicker是一个组件,通过点运算符进行调用
const MyComponents = {
    DatePicker: function DatePicker(props) {
        return <div>Imagine a {props.color} datepicker here.</div>
    }
}

function BlueDatePicker() {
    return <MyComponents.DatePicker color="blue" />
}

用户自定义组件必须首字母大写

当一个元素是小写开头的时候,一般被引用为内建组件,比如<div>或者<span>,会给React.createElement传入一个字符串div或者span,而大写字母开头的组件比如:<Foo />会编译成React.createElement(Foo)并且和组件定义联系起来。
我们建议使用大写字母开头来定义组件,如果你有一个组件,并且它以小写字母开头,应该为其分配一个大写字母开头的变量。
比如:

import React from 'react';
function hello(props) {
    return <div>Hello {props.toWhat}</div>;
}

function HelloWorld() {
    //这里的调用会出现问题,React会将hello标签误认为是HTML标签,因为它没有首字母大写
    //为了解决这个问题,将hello重命名为Hello就可以解决问题
    return <hello toWhat="World" />;
}

运行时选择类型

你不能够使用一般的表达式作为React元素的类型,如果你需要使用一个一般表达式来指定元素类型,就需要将这个表达式分配到大写字母开头的变量中,这种情况经常发生在你需要基于props来进行不同的渲染的时候。

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

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

//错误,不能够在React组件的类型上使用一般表达式
function Story(props) {
    return <components[props.storyType] story={props.story}>
}
//正确,JSX类型可以是一个大写字母开头的变量
function Story(props) {
    const SpecificStory = components[props.storyType];
    return <SpecificStory story={props.story}>
}

JSX中的props

下面有几种不同的方式在JSX中指定props

JavaScript表达式

你可以传递任何JavaScript表达式作为props,但是要通过花括号来进行包裹

//对于下面这个组件,props.foo的值将为10,因为表达式1+2+3+4的结果为10
<MyComponent foo={1 + 2 + 3 + 4} />

if表达式和for循环在JavaScript中并不是表达式,所以不能直接用在JSX中,相反,你可以将这些代码放在周围的代码中:

function NumberDescriber(props) {
    let description;
    //将逻辑表达式提出到JSX语句外部
    if (props.number % 2 === 0) {
        description = <strong>even</strong>;
    } else {
        description = <i>odd</i>;
    }
    return <div>{props.number} is an {description} number.</div>;
}

字符串语法

你可以传递一个字符串作为props:

//下面两个表达式是等价的
<MyComponents message="hello world" />
<MyComponents message={'hello world'} />

当你传递一个字符串的时候,这个值是非HTML保有的:

//下面两个表达式也是等价的
<MyComponent message="&lt;3" />
<MyComponent message={"<3"} />

props默认为True

如果你没有为某个属性传递一个值,那这个属性的默认值为true

//下面两个JSX表达式是等价的
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />

一般来说,我们不建议使用默认值,因为ES6语法中的对象简写{foo}等价于{foo: foo},所以这样容易混淆,只有这个行为和在HTML中的写法相同的时候,才这么使用。

扩展属性

如果你已经有了一个props的对象变量,并且希望将这个变量传递给JSX,可以使用...作为扩展运算符来将整个对象传递给props:

//下面连个函数是等价的
function App1() {
    return <Greeting firstName="Ben" lastName="Hector" />
}
function App2() {
    const props = { firstName: "Ben", lastName: "Hector" };
    return <Greeting {...props} />
}

这种语法很容易去创建一个易于继承的容器,但是这可能会使你的代码变得很混乱,因为你可能会传递许多不相关的属性给子元素。

JSX中的子元素

在包含了一个开放标签和一个闭合标签的JSX表达式中,在这些标签当中的内容会传递一个特殊的属性:props.children有几种方法可以进行传递。

字符串语法

你可以在开始和结束标签之中放置一个字符串,并且props.children也会是字符串,这对于许多内联HTML元素非常好用。

<MyComponent>Hello world!</MyComponent>

上面的代码在JSX中是明显可用的,并且在MyComponent中的props.children属性是字符串"Hello world!",HTML是非保有的,所以你可以你可以使用这种方法来写HTML:

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

JSX移除了一行开头和结束的空格(相当于调用了一次trim()函数),并且也会移除空行,标签附近的新行会被删除,字符串中间的新行会被解析为一个空格:

//下面的几种JSX语法渲染得到的结果都是相同的
<div>Hello World</div>

<div>
    Hello World
</div>

<div>
    Hello
    World
</div>

<div>

    Hello World
</div>

JSX子元素

你可以提供更多的JSX元素作为子元素,这对于渲染嵌套组件非常好用:

<MyContainer>
    <MyFirstComponent />
    <MySecondComponent />
</MyContainer>

你可以混合多种不同类型的子元素,所以你可以使用字符串在JSX子元素中:

<div>
    Here is a list:
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
    </ul>
</div>

一个React组件不能返回多个React元素,但是一个单独的JSX可以有多个子元素,所以如果你希望一个组件返回多个元素的时候,你可以将这些元素包裹在一个div中。

JavaScript表达式

你可以传递任何JavaScript表达式作为子元素,通过闭合的{},比如:

//下面两个表达式有相同的渲染结果
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>

这对于渲染一个随机长度的JSX表达式是十分有用的:

function Item(props) {
    return <li>{props.message}</li>
}

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

JavaScript表达式可以混合多个其他类型的子元素,可以使用在字符串模板里面:

function Hello(props) {
    return <div>Hello {props.addressee}! </div>
}

函数作为子元素

正常情况下,JavaScript表达式插入JSX的时候都是字符串,React元素或者一个上述元素的列表,然而props.children像其他属性一样,可以传递任何类型的数据,并不仅仅只是React知道如何渲染的那些数据,比如,如果你有一个自定义组件,你也可以用一个回调函数作为props.children

function ListOfTenThings() {
    return (
        <Repeat numTimes={10}>
            {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
    );
}

function Repeat(props) {
    let items = [];
    for (let i=0; i<props.numTimes; i++) {
        items.push(props.children(i));
    }
    return <div>{items}</div>
}

传递给自定义组件的子元素可以是任何类型的,然后在渲染之前,组件会被转化为可以被React识别的类型,这种使用方法并不常见,但是如果需要在JSX中使用的时候也是没有问题的。

被忽略的Boolean, Null和Undefined

false,null,undefined,true是可用的子元素,这些元素不会被渲染:

//下面的几个组件都有相同的渲染效果。
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{true}</div>

这在条件渲染某些React元素的时候有些作用的。

//下面的代码会渲染出一个<Header />,如果showHeader为true的话
<div>
    {showHeader && <Header />}
    <Content />
</div>

需要注意的是一些”falsy”值,比如数字0,仍然会被React进行渲染:

//下面的代码并不会得到预期的结果,如果props.messages如果没有值的话,就会打印0
<div>
    {props.messages.length &&
        <MessageList messages={props.messages} />
    }
</div>

如果需要得到正确的输出,那么需要保证&&符号之前必须是boolean值

<div>
    {
        props.messages.length > 0 &&
        <MessageList messages={props.messages} />
    }
</div>

相反,如果你希望有false,true,null,undefined被打印到页面上的时候,你需要将其先转换为字符串:

<div>
    My JavaScript variable is {String(myVariable)}.
</div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值