React 使用JSX或者TSX渲染页面

server/2024/9/24 9:37:19/

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是什么感觉,是时候进入下一章了,我们将更深入地了解组件、属性和状态。


http://www.ppmy.cn/server/45116.html

相关文章

备受推崇的公司文件加密文件推荐榜单

迄今为止&#xff0c;加密依然是最有效的用于保护数据、通讯安全的手段之一 在数字化时代&#xff0c;文件加密软件成为了保护个人和企业数据安全的重要工具。随着技术的不断进步&#xff0c;市场上涌现出了众多优秀的文件加密软件。 以下十款文件加密软件因其出色的性能、易…

电脑同时配置两个版本mysql数据库常见问题

1.配置时&#xff0c;要把bin中的mysql.exe和mysqld.exe 改个名字&#xff0c;不然两个版本会重复&#xff0c;当然&#xff0c;在初始化数据库的时候&#xff0c;如果时57版本的&#xff0c;就用mysql57(已经改名的)和mysqld57 代替 mysql 和 mysqld 例如 mysql -u root -p …

Metasploit渗透测试框架

Metasploit简介 Metasploit 是The Metasploit framework的简称,框架由多个module组成 是一款开源安全漏洞利用和测试工具&#xff0c;集成了各种平台上常见的漏洞&#xff0c;并持续保持更新。 metasploit涵盖了渗透测试中全过程&#xff0c;你可以在这个框架下利用现有的Pa…

vue富文本层级高

在Vue中处理复杂的层级关系&#xff0c;通常可以使用组件和递归组件来构建富文本树形结构。以下是一个简单的例子&#xff0c;展示了如何使用Vue组件来构建一个树形控件 <template><div><tree-node v-for"node in treeData" :key"node.id&quo…

如何让你的网站能通过域名访问

背景 当我们租一台云服务器&#xff0c;并在上面运行了一个Web服务&#xff0c;我们可以使用云服务器的公网IP地址进行访问&#xff0c;如下&#xff1a; 本文主要记录如何 实现让自己的网站可以通过域名访问。 买域名 可以登录腾讯云等主流公有云平台的&#xff0c;购买域名…

如何在中国网上发布文章

随着互联网的迅猛发展&#xff0c;网上发布文章已经成为一种重要的传播方式。而在中国&#xff0c;作为世界上最大的互联网市场&#xff0c;如何在中国网上发布文章成为了许多人关注的焦点。媒介多多网发稿平台作为一个专业的发稿平台&#xff0c;为广大作者提供了很好的发布文…

SQL 语言:嵌入式 SQL 和动态 SQL

文章目录 基本概述嵌入式 SQL动态 SQL总结 基本概述 嵌入式SQL和动态SQL是两种在应用程序中嵌入和使用SQL语句的方法。它们都允许开发人员在编程语言中编写SQL语句&#xff0c;以便在应用程序中执行数据库操作。然而&#xff0c;这两种方法在实现方式、性能和灵活性方面存在一…

[音视频]ffmepg常用命令

ffmpeg 在音视频的世界里&#xff0c;ffmpeg可是如雷贯耳的存在&#xff0c;学习音视频开发&#xff0c;ffmpeg是必须掌握的技能 常用命令 保存m3u8文件 ffmpeg -i http://xxxxx/test.m3u8 -c copy result.mp4