当前位置: 首页 > news >正文

React 使用JSX或者TSX渲染页面

02 Rendering with JSX

Your first JSX content

In this section, we’ll implement the obligatory " Hello, World " JSX application. At this point, we’re just dipping our toes in the water; more in-depth examples will follow. We’ll also discuss what makes this syntax work well for declarative UI structures.

在本节中,我们将实现必需的“Hello, World”JSX应用程序。在这一点上,我们只是把脚趾伸进水里;后面会有更深入的例子。我们还将讨论是什么使这种语法能够很好地用于声明性UI结构。

Hello JSX

先创建一个基于ts的vite项目:

npm create vite

修改src/main.tsx:

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";ReactDOM.createRoot(document.getElementById("root")!).render(<React.StrictMode><App /></React.StrictMode>
);

Without further ado, here’s your first JSX application:

话不多说,下面是您的第一个JSX应用程序: src/App.tsx

function App() {return (<p>Hello, <strong>JSX</strong></p>);
}export default App;

Let’s walk through what’s happening here. The render() function takes JSX as an argument and renders it to the DOM node passed toReactDOM.createRoot() .The actual JSX content in this example renders a paragraph with some bold text inside. There’s nothing fancy going on here, so we could have just inserted this markup into the DOM directly as a plain string. However, the aim of this example is to show the basic steps involved in getting JSX rendered onto the page. Now, let’s talk a little bit about the declarative UI structure.

让我们来看看这里发生了什么。render()函数接受JSX作为参数,并将其呈现给传递给reactdom . createroot()的DOM节点。本例中的实际JSX内容呈现一个段落,其中包含一些粗体文本。这里没有什么特别的事情,所以我们可以直接将这个标记作为一个普通字符串插入DOM。但是,本示例的目的是展示将JSX呈现到页面上所涉及的基本步骤。现在,让我们讨论一下声明性UI结构。

Declarative UI structures

Before we move forward with more in-depth code examples, let’s take a moment to reflect on our " Hello, World " example. The JSX content was short and simple. It was also declarative because it described what to render, not how to render it. Specifically, by looking at the JSX, you can see that this component will render a paragraph and some bold text within it. If this were done imperatively, there would probably be some more steps involved, and they would probably need to be performed in a specific order.

在继续讨论更深入的代码示例之前,让我们花点时间回顾一下“Hello, World”示例。JSX的内容简短而简单。它也是声明性的,因为它描述了要呈现什么,而不是如何呈现。具体来说,通过查看JSX,您可以看到该组件将在其中呈现一个段落和一些粗体文本。如果这是命令式的,则可能会涉及到更多的步骤,并且可能需要以特定的顺序执行。

I find it helpful to think of declarative as structured and imperative as ordered. It’s much easier to get things right with a proper structure than to perform steps in a specific order.

我发现将陈述性看作是结构化的,命令式看作是有序的很有帮助。与按特定顺序执行步骤相比,用适当的结构把事情做好要容易得多。

The example we just implemented should give you a feel for what declarative React is all about. As we move forward in this chapter and throughout the book, the JSX markup will grow more elaborate. However, it’s always going to describe what is in the UI.The render() function tells React to take your JSX markup and transform it into JavaScript statements that update the UI in the most efficient way possible. This is how React enables you to declare the structure of your UI without having to think about carrying out ordered steps to update elements on the screen; an approach that often leads to bugs. Out of the box, React supports the standard HTML tags that you would find on any HTML page. Unlike static HTML, React has unique conventions that should be followed when using HTML tags.…

我们刚刚实现的例子应该会让你对声明式React有一个大致的了解。随着本章和本书的深入,JSX标记将变得更加复杂。不过,它总是会描述UI中的内容。render()函数告诉React获取您的JSX标记并将其转换为JavaScript语句,以最有效的方式更新UI。这就是React如何让你声明UI的结构,而不必考虑执行有序的步骤来更新屏幕上的元素;一种经常导致bug的方法。React开箱即用,支持在任何HTML页面上都能找到的标准HTML标记。与静态HTML不同,React在使用HTML标签…时应该遵循独特的约定

Rendering HTML

At the end of the day, the job of a React component is to render HTML into the DOM browser. This is why JSX has support for HTML tags out of the box. In this section, we’ll look at some code that renders a few of the available HTML tags. Then, we’ll cover some of the conventions that are typically followed in React projects when HTML tags are used.

归根结底,React组件的工作是将HTML呈现到DOM浏览器中。这就是JSX支持HTML标记的原因。在本节中,我们将看一些呈现一些可用HTML标记的代码。然后,我们将介绍在React项目中使用HTML标记时通常遵循的一些约定。

Built-in HTML tags

When we render JSX, element tags reference React components. Since it would be tedious to have to create components for HTML elements, React comes with HTML components. We can render any HTML tag in our JSX, and the output will be just as we’d expect. Now, let’s try rendering some of these tags:

当我们渲染JSX时,元素标签引用React组件。因为为HTML元素创建组件会很繁琐,所以React自带了HTML组件。我们可以在JSX中呈现任何HTML标记,输出将与我们所期望的一样。现在,让我们尝试渲染其中的一些标签:

function App() {return (<div><h1>标题标签</h1><p>段落标签</p><ul><li>列表标签</li><li>列表标签</li><li>列表标签</li></ul></div>);
}export default App;

Don’t worry about the formatting of the rendered output for this example. We’re making sure that we can render arbitrary HTML tags, and they render as expected, without any special definitions and imports.

对于本例,不要担心呈现输出的格式。我们要确保可以呈现任意HTML标记,并且它们可以按照预期呈现,而不需要任何特殊的定义和导入。

HTML elements rendered using JSX closely follow regular HTML element syntax with a few subtle differences regarding case-sensitivity and attributes.

使用JSX呈现的HTML元素非常遵循常规HTML元素语法,只是在区分大小写和属性方面有一些细微的区别。

HTML tag conventions

When you render HTML tags in JSX markup, the expectation is that you’ll use lowercase for the tag name. In fact, capitalizing the name of an HTML tag will fail. Tag names are case-sensitive and non-HTML elements are capitalized. This way, it’s easy to scan the markup and spot the built-in HTML elements versus everything else.You can also pass HTML elements any of their standard properties. When you pass them something unexpected, a warning about the unknown property is logged. Here’s an example that illustrates these ideas:

在JSX标记中呈现HTML标记时,期望使用小写的标记名。事实上,将HTML标记的名称大写将会失败。标签名称区分大小写,非html元素大写。这样,就很容易扫描标记并找出内置的HTML元素和其他元素。您还可以将HTML元素的任何标准属性传递给它们。当您向它们传递一些意外的内容时,将记录有关未知属性的警告。这里有一个例子可以说明这些想法:

function App() {return (<div><Button title="这是一个按钮" foo="bar">这是一个按钮</Button></div>);
}export default App;

When you run this example, it will fail to compile because React doesn’t knowabout the <Button> element; it only knows about <button> .

当你运行这个例子时,它会编译失败,因为React不知道<Button>元素;它只知道<button>

Later on in the book, I’ll cover property validation for the components that you make. This avoids silent misbehavior, as seen with the foo property in this example.

在本书的后面,我将介绍您所创建的组件的属性验证。这避免了无声的错误行为,如本例中的foo属性所示。

You can use any valid HTML tags as JSX tags, as long as you remember that they’re case-sensitive and that you need to pass the correct attribute names. In addition to simple HTML tags that only have attribute values, you can use HTML tags to describe the structure of your page content.

可以使用任何有效的HTML标记作为JSX标记,只要记住它们是区分大小写的,并且需要传递正确的属性名。除了只有属性值的简单HTML标记之外,还可以使用HTML标记来描述页面内容的结构。

Describing UI structures

JSX is capable of describing screen elements in a way that ties them together to form a complete UI structure. Let’s look at some JSX markup that declares a more elaborate structure than a single paragraph:

JSX能够以一种将屏幕元素连接在一起形成完整UI结构的方式来描述屏幕元素。让我们看看一些JSX标记,它们声明了一个比单个段落更复杂的结构:

function App() {return (<section><header><h1>头部内容</h1></header><nav><a href="item">导航链接</a></nav><main><p>主体内容...</p></main><footer><small>版权所有 &copy; 张大鹏</small></footer></section>);
}export default App;

This JSX markup describes a fairly sophisticated UI structure. Yet, it’s easier to read than imperative code because it’s XML, and XML is good for concisely expressing a hierarchical structure. This is how we want to think of our UI when it needs to change – not as an individual element or property, but the UI as a whole.

这个JSX标记描述了一个相当复杂的UI结构。然而,它比命令式代码更容易阅读,因为它是XML,而XML适合简洁地表达层次结构。这就是我们在需要改变UI时要考虑的方式——不是作为单个元素或属性,而是作为一个整体。

There are a lot of semantic elements in this markup describing the structure of the UI. For example, the <header> element describes the top part of the page where the title is, and the <main> element describes where the main page content goes. This type of complex structure makes it clearer for developers to reason about. But before we start implementing dynamic JSX markup, let’s create some of our own JSX components.

在这个标记中有很多描述UI结构的语义元素。例如,<header>元素描述了页面顶部的标题所在位置,而<main>元素描述了主页内容的位置。这种类型的复杂结构使开发人员能够更清楚地进行推理。但在开始实现动态JSX标记之前,让我们先创建一些自己的JSX组件。

Creating your own JSX elements

Components are the fundamental building blocks of React. In fact, components are the vocabulary of JSX markup. In this section, we’ll see how to encapsulate HTML markup within a component. We’ll build examples that nest custom JSX elements and learn how to namespace components.

组件是React的基本构建块。实际上,组件是JSX标记的词汇表。在本节中,我们将看到如何在组件中封装HTML标记。我们将构建嵌套自定义JSX元素的示例,并学习如何命名组件。

Encapsulating HTML

We create new JSX elements so that we can encapsulate larger structures. This means that instead of having to type out complex markup, you can use your custom tag. The React component returns the JSX that goes where the tag is used. Let’s look at the following example:

我们创建新的JSX元素,以便封装更大的结构。这意味着您可以使用自定义标记,而不必键入复杂的标记。React组件返回到使用标记的地方的JSX。让我们看看下面的例子:

src/MyComponent.tsx

function MyComponent() {return (<section><h1>我的第一个自定义组件</h1><p>我也可以使用React创建自定义的组件了。。。</p></section>);
}export default MyComponent;

接着修改src/App.tsx,使用这个自定义的组件:

import MyComponent from "./MyComponent";function App() {return (<section><header><h1>头部内容</h1></header><nav><a href="item">导航链接</a></nav><main><p>主体内容...</p><MyComponent /></main><footer><small>版权所有 &copy; 张大鹏</small></footer></section>);
}export default App;

Here’s what This is the first React component that we’ve implemented, so let’s take a moment to dissect what’s going on here. We created a function called MyComponent , where in return statement we put our HTML tags. This is how we create a new JSX element. As you can see in the call to render() , you’re rendering a <MyComponent> element.The HTML that this component encapsulates is returned from the function we created. In this case, when the JSX is rendered by react-dom , it’s replaced by a <section> element and everything within it.

这是我们实现的第一个React组件,所以让我们花点时间来分析一下这里发生了什么。我们创建了一个名为MyComponent的函数,在返回语句中放置HTML标记。这就是我们如何创建一个新的JSX元素。正如你在render()的调用中看到的,你正在渲染一个<MyComponent>元素。该组件封装的HTML是从我们创建的函数返回的。在这种情况下,当react-dom渲染JSX时,它被一个<section>元素和其中的所有内容所替换。

When React renders JSX, any custom elements that you use must have their corresponding React component within the same scope. In the preceding example, the MyComponent function was declared in the same scope as the call to render() , so everything worked as expected. Usually, you’ll import components, adding them to the appropriate scope. You’ll see more of this as you progress through the book.

当React呈现JSX时,你使用的任何自定义元素都必须在相同的作用域中拥有相应的React组件。在前面的例子中,MyComponent函数被声明在与render()调用相同的作用域中,所以一切都如预期的那样工作。通常,您将导入组件,并将它们添加到适当的作用域。随着阅读的深入,你会看到更多这样的内容。

HTML elements such as <div> often take nested child elements. Let’s see whether we can do the same with JSX elements, which we create by implementing components.

<div>这样的HTML元素通常带有嵌套的子元素。让我们看看是否可以对通过实现组件创建的JSX元素执行相同的操作。

Nested elements

Using JSX markup is useful for describing UI structures that have parent-child relationships. Child elements are created by nesting them within another component: the parent. For example, a <li> tag is only useful as the child of a <ul> tag or a <ol> tag—you’re probably going to make similar nested structures with your own React components. For this, you need to use the children property. Let’s see how this works. Here’s the JSX markup:

使用JSX标记对于描述具有父子关系的UI结构非常有用。子元素是通过将它们嵌套在另一个组件中创建的:父组件。例如,<li>标签仅作为<ul>标签或<ol>标签的子标签有用-您可能会在自己的React组件中制作类似的嵌套结构。为此,您需要使用children属性。让我们看看它是如何工作的。下面是JSX标记:

修改 src/App.tsx:

import MyComponent from "./MyComponent";
import MySection from "./MySection";
import MyButton from "./MyButton";function App() {return (<section><header><h1>头部内容</h1></header><nav><a href="item">导航链接</a></nav><main><p>主体内容...</p><MyComponent /><MySection><MyButton>自定义的按钮文本</MyButton></MySection></main><footer><small>版权所有 &copy; 张大鹏</small></footer></section>);
}export default App;

You’re importing two of your own React components: MySection and MyButton . Now, if you look at the JSX markup, you’ll notice that <MyButton> is a child of <MySection> . You’ll also notice that the MyButton component accepts text as its child, instead of more JSX elements. Let’s see how these components work, starting with MySection :

您正在导入两个自己的React组件:MySection和MyButton。现在,如果你看一下JSX标记,你会注意到<MyButton><MySection>的子元素。您还会注意到MyButton组件接受文本作为它的子元素,而不是更多的JSX元素。让我们从MySection开始,看看这些组件是如何工作的:

新增 src/MySection.tsx

export default function MySection(props) {return (<section><h2>我的自定义片段组件</h2>{/* 这里渲染子元素 */}{props.children}</section>);
}

This component renders a standard <section> HTML element, a heading, and then {props.children} . It’s this last piece that allows components to access nested elements or text, and to render them.

这个组件呈现一个标准的<section> HTML元素,一个标题,然后是{props。孩子}。正是这最后一部分允许组件访问嵌套的元素或文本,并呈现它们。

The two braces used in the preceding example are used for JavaScript expressions. I’ll touch on more details of the JavaScript expression syntax found in JSX markup in the following section.

前面示例中使用的两个大括号用于JavaScript表达式。在下一节中,我将详细介绍JSX标记中的JavaScript表达式语法。

Now, let’s look at the MyButton component:

现在,让我们看看MyButton组件:

新增:src/MyButton.tsx

export default function MyButton(props) {return <button>{props.children}</button>;
}

This component uses the exact same pattern as MySection ; it takes the{props.children} value and surrounds it with markup. React handles the details for you. In this example, the button text is a child of MyButton , which is, in turn, a child of MySection . However, the button text is transparently passed through MySection . In other words, we didn’t have to write any code in MySection to make sure that MyButton got its text. Pretty cool, right?

这个组件使用与MySection完全相同的模式;它使用{props。Children}值,并用标记包围它。React会为你处理这些细节。在这个例子中,按钮文本是MyButton的子元素,而MyButton又是MySection的子元素。但是,按钮文本是透明地通过MySection传递的。换句话说,我们不需要在MySection中编写任何代码来确保MyButton获得它的文本。很酷,对吧?

We can further organize our components by placing them within a namespace.

我们可以通过将组件放置在名称空间中来进一步组织组件。

Namespaced components

The custom elements that you’ve created so far have used simple names. A namespace provides an organizational unit for your components so that related components can share the same namespace prefix. Instead of writing <MyComponent> in your JSX markup, you would write <MyNamespace.MyComponent> . This makes it clear that MyComponent is part of MyNamespace .Typically, MyNamespace would also be a component. The idea of namespacing is to have a namespace component render its child components using the namespace syntax. Let’s take a look at an example:

到目前为止,您创建的自定义元素都使用了简单的名称。名称空间为组件提供了一个组织单元,以便相关组件可以共享相同的名称空间前缀。而不是写’<MyComponent>在你的JSX标记中,你应该写<MyNamespace.MyComponent >。这清楚地表明MyComponent是MyNamespace的一部分。通常,MyNamespace也是一个组件。名称空间的思想是让名称空间组件使用名称空间语法呈现其子组件。让我们来看一个例子:

新增 src/MyComponent2.tsx

function MyComponent(props) {return <div>{props.children}</div>;
}
function First() {return <p>第一个组件...</p>;
}
function Second() {return <p>第二个组件...</p>;
}
MyComponent.First = First;
MyComponent.Second = Second;function MyComponent2() {return (<MyComponent><MyComponent.First /><MyComponent.Second /></MyComponent>);
}export default MyComponent2;

This markup renders a <MyComponent> element with two children. Instead of writing <First> , we write <MyComponent.First> , and the same with <MyComponent.Second> . We want to explicitly show that First and Second belong to MyComponent within the markup.Now, let’s take a look at the MyComponent module:

这个标记呈现了一个带有两个子元素的<MyComponent>元素。我们不写<First>,而是写<MyComponent.First>, <MyComponent.Second>也一样。我们想要显式地显示First和Second属于标记中的MyComponent。现在,让我们来看看MyComponent模块:

function MyComponent(props) {return <div>{props.children}</div>;
}
function First() {return <p>第一个组件...</p>;
}
function Second() {return <p>第二个组件...</p>;
}
MyComponent.First = First;
MyComponent.Second = Second;

This module declares MyComponent as well as the other components that fall under this namespace ( First and Second ). It assigns the components to the namespace component ( MyComponent ) as function object properties. There are a number of things that you could change in this module. For example, you don’t have to directly export First and Second since they’re accessible through MyComponent . You also don’t need to define everything in the same module; you could import First and Second and assign them as function object properties. Using namespaces is completely optional, and, if you use them, you should use them consistently.You now know how to build your own React components that introduce new JSX tags in your markup. The components that we’ve looked at so far in this chapter have been static. That is, once we rendered them, they were never updated. JavaScript expressions are the dynamic pieces of JSX and are what cause React to update components.

这个模块声明了MyComponent以及这个命名空间下的其他组件(First和Second)。它将组件作为函数对象属性分配给命名空间组件(MyComponent)。在这个模块中,您可以更改许多内容。例如,你不必直接导出First和Second,因为它们可以通过MyComponent访问。你也不需要在同一个模块中定义所有的东西;您可以导入First和Second,并将它们指定为函数对象属性。使用名称空间是完全可选的,如果要使用它们,应该始终如一地使用它们。现在您知道了如何构建自己的React组件,在标记中引入新的JSX标记。到目前为止,我们在本章中看到的组件都是静态的。也就是说,一旦我们渲染了它们,它们就永远不会更新。JavaScript表达式是JSX的动态部分,是React更新组件的原因。

Using JavaScript expressions

As you saw in the preceding section, JSX has a special syntax that allows you to embed JavaScript expressions. Any time React renders JSX content, expressions in the markup are evaluated. This is the dynamic aspect of JSX, and in this section, you’ll learn how to use expressions to set property values and element text content. You’ll also learn how to map collections of data to JSX elements.

正如您在上一节看到的,JSX有一种特殊的语法,允许您嵌入JavaScript表达式。每当React呈现JSX内容时,都会计算标记中的表达式。这是JSX的动态方面,在本节中,您将学习如何使用表达式来设置属性值和元素文本内容。您还将学习如何将数据集合映射到JSX元素。

Dynamic property values and text

Some HTML property or text values are static, meaning that they don’t change as JSX markup is re-rendered. Other values, the values of properties or text, are based on data that is found elsewhere in the application. Remember, React is just the view layer. Let’s look at an example so that you can get a feel for what the JavaScript expression syntax looks like in JSX markup:

一些HTML属性或文本值是静态的,这意味着它们在重新呈现JSX标记时不会改变。其他值(属性值或文本值)基于在应用程序中其他地方找到的数据。记住,React只是视图层。让我们来看一个例子,这样你就可以感受到JavaScript表达式在JSX标记中的语法是什么样的:

新增 src/MyComponent3.tsx:

function MyComponent3() {const enabled = false;const text = "一个按钮";const placeholder = "请输入账号";const size = 50;return (<section><button disabled={!enabled}>{text}</button><input placeholder={placeholder} size={size} /></section>);
}export default MyComponent3;

Anything that is a valid JavaScript expression, including nested JSX, can go in between the curly braces: {} . For properties and text, this is often a variable name or object property. Notice, in this example, that the !enabled expression computes a Boolean value.

任何有效的JavaScript表达式,包括嵌套的JSX,都可以放在花括号{}之间。对于属性和文本,这通常是一个变量名或对象属性。注意,在本例中,启用的表达式计算一个布尔值。

Primitive JavaScript values are straightforward to use in JSX syntax. But what if you have an object or array that you need to transform into JSX elements?

原始JavaScript值在JSX语法中使用很简单。但是,如果需要将对象或数组转换为JSX元素,该怎么办呢?

Handling events

In React, you can easily pass events to components to handle user interactions such as button clicks, form submissions, and mouse movements. This allows you to create interactive and responsive user interfaces. React provides a convenient way to attach event handlers directly to components using a syntax similar to how you would use the addEventListener and removeEventListener methods in traditional JavaScript.To illustrate this, let’s consider an example where we want to handle a button click event in a React component:

在React中,您可以轻松地将事件传递给组件来处理用户交互,例如按钮单击、表单提交和鼠标移动。这允许您创建交互式和响应式用户界面。React提供了一种方便的方式来直接将事件处理程序附加到组件上,使用类似于传统JavaScript中使用addEventListener和removeEventListener方法的语法。为了说明这一点,让我们考虑一个例子,我们想要处理一个React组件中的按钮点击事件:

新增:src/MyComponent4.tsx

function MyComponent4() {const text = "点我试试";const onButtonClick = () => {alert("试试就试试");};return (<section><button onClick={onButtonClick}>{text}</button></section>);
}export default MyComponent4;

In this example, we define a function called handleClick that will be called when the button is clicked. We then attach this function as an event handler to the onClick property of the <button> component. Whenever the button is clicked, React will invoke the handleClick function.Compared to using addEventListener and removeEventListener in traditional JavaScript, React abstracts away some of the complexities. With React’s event handling, you don’t have to worry about manually attaching and detaching event listeners to DOM elements. React manages the event delegation and provides a more declarative approach to handling events within components.By using this approach, you can easily pass events to child components, handle them in parent components, or even propagate events through multiple levels of nested components. This helps in building a modular and reusable component architecture.It’s important to note that when defining event handlers in React, you don’t invoke the function immediately by adding parentheses after the function name, as you would in regular JavaScript. Instead, you provide a reference to the function, allowing React to call it when the event occurs.

在本例中,我们定义了一个名为handleClick的函数,该函数将在单击按钮时被调用。然后我们将这个函数作为事件处理程序附加到<button>组件的onClick属性上。每当单击按钮时,React将调用handleClick函数。与在传统JavaScript中使用addEventListener和removeEventListener相比,React抽象了一些复杂性。使用React的事件处理,您不必担心手动将事件侦听器附加和分离到DOM元素。React管理事件委托,并提供一种更具声明性的方法来处理组件内的事件。通过使用这种方法,您可以轻松地将事件传递给子组件,在父组件中处理它们,甚至可以通过多层嵌套组件传播事件。这有助于构建模块化和可重用的组件体系结构。需要注意的是,在React中定义事件处理程序时,不会像在常规JavaScript中那样,通过在函数名后面添加括号来立即调用函数。相反,您提供对该函数的引用,允许React在事件发生时调用它。

In addition to the onClick event, React supports a wide range of other events, such as onChange , onSubmit , onMouseOver , and many more. You can attach event handlers to various elements like buttons, input fields, checkboxes, and so on.

除了onClick事件,React还支持很多其他事件,比如onChange、onSubmit、onMouseOver等等。您可以将事件处理程序附加到各种元素,如按钮、输入字段、复选框等。

Remember, React promotes a unidirectional data flow, which means that data flows from parent components to child components. To pass data or information from child components back to the parent component, you can define callbacks as props and invoke them with the necessary data. In the upcoming chapters of this book, we will delve deeper into event handling in React and how to create custom callbacks.

请记住,React促进了单向数据流,这意味着数据从父组件流向子组件。要将数据或信息从子组件传递回父组件,您可以将回调定义为道具,并使用必要的数据调用它们。在本书接下来的章节中,我们将深入探讨React中的事件处理以及如何创建自定义回调。

Mapping collections to elements

Sometimes, you need to write JavaScript expressions that change the structure of your markup. In the preceding section, you learned how to use JavaScript expression syntax to dynamically change the property values of JSX elements. What about when you need to add or remove elements based on JavaScript collections?

有时,需要编写改变标记结构的JavaScript表达式。在上一节中,您学习了如何使用JavaScript表达式语法动态更改JSX元素的属性值。当您需要基于JavaScript集合添加或删除元素时该怎么办?

Throughout the book, when I refer to a JavaScript collection, I’m referring to both plain objects and arrays. Or, more generally, anything that’s iterable.

在本书中,当我提到JavaScript集合时,我指的是普通对象和数组。或者,更一般地说,任何可迭代的东西。

The best way to dynamically control JSX elements is to map them from a collection. Let’s look at an example of how this is done:

动态控制JSX元素的最佳方法是从集合映射它们。让我们来看一个例子:

新增:src/MyComponent5.tsx

function MyComponent5() {const array = ["张三", "李四", "王五"];const object = {1: "张三",2: "李四",3: "王五",};return (<section><h1>渲染数组</h1><ul>{array.map((i) => (<li key={i}>{i}</li>))}</ul><h1>渲染对象</h1><ul>{Object.keys(object).map((i) => (<li key={i}><strong>{i}: </strong>{object[i]}</li>))}</ul></section>);
}export default MyComponent5;

The first collection is an array called array, populated with string values. Moving down to the JSX markup, you can see the call to array.map() , which returns a new array. The mapping function is actually returning a JSX element ( <li> ), meaning that each item in the array is now represented in the markup.

第一个集合是一个名为array的数组,用字符串值填充。向下移动到JSX标记,可以看到对array.map()的调用,它返回一个新数组。映射函数实际上返回一个JSX元素(<li>),这意味着数组中的每个项现在都在标记中表示。

The result of evaluating this expression is an array. Don’t worry – JSX knows how to render arrays of elements.

对这个表达式求值的结果是一个数组。不用担心,JSX知道如何呈现元素数组。

The object collection uses the same technique, except you have to call Object.keys() and then map this array. What’s nice about mapping collections to JSX elements on the page is that you can control the structure of React components based on the collected data. This means that you don’t have to rely on imperative logic to control the UI.

对象集合使用相同的技术,只是您必须调用object .keys(),然后映射这个数组。将集合映射到页面上的JSX元素的好处是,您可以根据收集到的数据控制React组件的结构。这意味着您不必依赖命令式逻辑来控制UI。

JavaScript expressions bring JSX content to life. React evaluates expressions and updates the HTML content based on what has already been rendered and what has changed. Understanding how to utilize these expressions is important because they’re one of the most common day-to-day activities of any React developer. Now it’s time to learn how to group together JSX markup without relying on HTML tags to do so.

JavaScript表达式使JSX内容栩栩如生。React计算表达式并根据已经呈现的内容和更改的内容更新HTML内容。理解如何使用这些表达式很重要,因为它们是React开发人员最常见的日常活动之一。现在是时候学习如何在不依赖HTML标记的情况下将JSX标记分组。

Building fragments of JSX

Fragments are a way to group together chunks of markup without having to add unnecessary structure to your page. For example, a common approach is to have a React component return content wrapped in a <div> element. This element serves no real purpose and adds clutter to the DOM.Let’s look at an example. Here are two versions of a component. One uses a wrapper element, and one uses the new fragment feature:

片段是一种将标记块组合在一起的方法,而不必向页面添加不必要的结构。例如,一种常见的方法是将React组件返回的内容包装在<div>元素中。这个元素没有任何实际用途,而且给DOM增加了混乱。让我们来看一个例子。下面是一个组件的两个版本。一个使用包装器元素,另一个使用新的片段特性:

新增:src/MyComponent6.tsx

import * as ReactDOM from “react-dom”;
import WithoutFragments from “./WithoutFragments”;
import WithFragments from “./WithFragments”;
const root = ReactDOM.createRoot(document.getElementById(“root”));
root.render(
<div>
<WithoutFragments />
<WithFragments />
</div>
);

The two elements rendered are <WithoutFragments> and <WithFragments> .

Let’s compare the two approaches now.

Using wrapper elements

The first approach is to wrap sibling elements in <div> . Here’s what the source looks like:

function WithoutFragments() {return (<div><h1>不使用空白片段,使用div</h1><p>额外的代码。。。</p></div>);
}function WithFragments() {return (<><h1>使用空白片段</h1><p>没有任何无效的HTML代码</p></>);
}function MyComponent6() {return (<div><WithoutFragments /><WithFragments /></div>);
}export default MyComponent6;

T he essence of this component is the <h1> and <p> tags. Yet, in order to return them from render() , you have to wrap them with <div> . Indeed, inspecting the DOM using your browser dev tools reveals that <div> does nothing but add another level of structure:

Now, imagine an app with lots of these components—that’s a lot of pointless elements! Let’s see how to use fragments to avoid unnecessary tags.

Using fragments

Let’s take a look at the WithFragments component, where we have avoided using unnecessary tags:

function WithFragments() {return (<><h1>使用空白片段</h1><p>没有任何无效的HTML代码</p></>);
}

Instead of wrapping the component content in <div> , the <> element is used. This is a special type of element that indicates that only its children need to be rendered. You can see the difference compared to the WithoutFragments component if you inspect the DOM:

With the advent of fragments in JSX markup, we have less HTML rendered on the page because we don’t have to use tags such as

for the sole purpose of grouping elements together. Instead, when a component renders a fragment, React knows to render the fragment’s child element wherever the component is used.So, fragments enable React components to render only the essential elements; no more elements that serve no purpose will appear on the rendered page.

Summary

In this chapter, you learned about the basics of JSX, including its declarative structure, which leads to more maintainable code. Then, you wrote some code to render some basic HTML and learned about describing complex structures using JSX; every React application has at least some structure.Next, you spent some time learning about extending the vocabulary of JSX markup by implementing your own React components, which is how you design your UI as a series of smaller pieces and glue them together to form the whole. Then, you learned how to bring dynamic content into JSX element properties, and how to map JavaScript collections to JSX elements, eliminating the need for imperative logic to control the UI display. Finally, you learned how to render fragments of JSX content, which prevents unnecessary HTML elements from being used.Now that you have a feel for what it’s like to render UIs by embedding declarative XML in your JavaScript modules, it’s time to move on to the next chapter, where we’ll take a deeper look at component, properties, and state.

在本章中,您学习了JSX的基础知识,包括它的声明性结构,它可以使代码更易于维护。然后,您编写了一些代码来呈现一些基本的HTML,并学习了如何使用JSX描述复杂的结构;每个React应用程序都至少有一些结构。接下来,您花了一些时间学习如何通过实现自己的React组件来扩展JSX标记的词汇表,这就是如何将UI设计为一系列较小的部分,并将它们粘合在一起形成整体。然后,学习了如何将动态内容引入JSX元素属性,以及如何将JavaScript集合映射到JSX元素,从而不需要命令式逻辑来控制UI显示。最后,您学习了如何呈现JSX内容的片段,这可以防止使用不必要的HTML元素。现在您已经了解了通过在JavaScript模块中嵌入声明性XML来呈现ui是什么感觉,是时候进入下一章了,我们将更深入地了解组件、属性和状态。

相关文章:

  • LLAMA3==shenzhi-wang/Llama3-8B-Chinese-Chat。windows安装不使用ollama
  • day21二叉树part07|530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先
  • 【网络运维的重要性】
  • 学习C++编程入门:时间、方法及经验分享
  • Unix环境高级编程--7-进程环境--7.1-7.2main函数-7.3进程退出
  • 人工智能初识
  • DOS学习-目录与文件应用操作经典案例-del
  • 2024年3月电子学会青少年软件编程 中小学生Python编程等级考试一级真题解析(选择题)
  • Flutter 中的 NestedScrollViewViewport 小部件:全面指南
  • 【Linux】Linux基本指令2
  • 哈希表练习题(2024/5/29)
  • 汇舟问卷:国外问卷调一天900
  • 数据结构(一)顺序表
  • HTML-JavaWeb
  • 一致性hash算法原理图和负载均衡原理-urlhash与least_conn案例
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • Angular4 模板式表单用法以及验证
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • Linux链接文件
  • node.js
  • Redash本地开发环境搭建
  • vue.js框架原理浅析
  • windows-nginx-https-本地配置
  • windows下使用nginx调试简介
  • 百度小程序遇到的问题
  • 多线程 start 和 run 方法到底有什么区别?
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 区块链将重新定义世界
  • 如何用vue打造一个移动端音乐播放器
  • 如何在 Tornado 中实现 Middleware
  • 推荐一款sublime text 3 支持JSX和es201x 代码格式化的插件
  • 原生 js 实现移动端 Touch 滑动反弹
  • 转载:[译] 内容加速黑科技趣谈
  • 7行Python代码的人脸识别
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • #Linux杂记--将Python3的源码编译为.so文件方法与Linux环境下的交叉编译方法
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (Arcgis)Python编程批量将HDF5文件转换为TIFF格式并应用地理转换和投影信息
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (附源码)spring boot火车票售卖系统 毕业设计 211004
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (转)chrome浏览器收藏夹(书签)的导出与导入
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .net 按比例显示图片的缩略图
  • .net 托管代码与非托管代码
  • @ 代码随想录算法训练营第8周(C语言)|Day57(动态规划)
  • [ 代码审计篇 ] 代码审计案例详解(一) SQL注入代码审计案例
  • [ 网络通信基础 ]——网络的传输介质(双绞线,光纤,标准,线序)
  • [2017][note]基于空间交叉相位调制的两个连续波在few layer铋Bi中的全光switch——
  • [BUG]Datax写入数据到psql报不能序列化特殊字符
  • [BZOJ 1040] 骑士
  • [C#]使用C#部署yolov8-seg的实例分割的tensorrt模型
  • [Contiki系列论文之2]WSN的自适应通信架构
  • [IE技巧] IE8中HTTP连接数目的变化
  • [LeetCode]剑指 Offer 40. 最小的k个数