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>版權所有 © 張大鵬</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>版權所有 © 張大鵬</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>版權所有 © 張大鵬</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
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是什么感覺,是時候進入下一章了,我們將更深入地了解組件、屬性和狀態。