React學習(3)-不可不知的JSX
- 2019 年 10 月 4 日
- 筆記

前言
本篇內容,對上一節的補充
- JSX中添加屬性有什麼要注意的?以及JSX中的子元素是怎麼操作的?
- 組件的大小寫問題,使用拓展運算符,以及怎麼循壞遍歷一個對象
- JSX中的prop指的是什麼?以及表單的labe應該要注意什麼?
以上問題即使自己很清楚,但是否有時卻總是道不清,說不明?那麼讀完本文,就豁然開朗了
JSX添加特定屬性
自定義標籤拓展了原生HTML標籤不具備的能力,最大的一個用處就是屬性傳值,標籤的屬性值,可以是字元串,變數對象
例如:如下所示
const element = <div divIndex ="0"></div>
當然也可以使用下面這種方式,是等價的,用一個大括弧將變數包裹起來
const element = <div divIndex={"0"}></div>
至於更多插值表達式內容,你可以看上一節的
這裡要提一下,在屬性中嵌入javascript表達式,不要在雙大括弧外面加上引號,例如,下面的是錯誤的
const element = <div divIndex="{ variable }"></div>
也就是說,對於字元串或者雙大括弧中的表達式,對於同一屬性,不能同時使用這兩種符號
**注意**
JSX語法是更接近Javascript而不是HTML,只是長得像而已,對於Reat中自定義組件的屬性名稱,使用camelCase
駝峰式命名來定義屬性的名稱,例如:定義JSX里的class屬性,classNamed而divindex變成divIndex
JSX中的子元素
在原生HTML標籤中,要是對於DOM結構樹熟悉的話,理解JSX的子元素也是比較容易的
原生HTML的標籤叫做節點,節點有節點屬性,以及節點的內容
如果一個標籤或者React組件沒有內容,你是可以使用/>
,單標籤來閉合的,就像XML語法一樣,例如如下所示
const element = <img src={ user.avatarUrl} />
JSX標籤裡面能夠包含很多個子元素
例如:如下所示
const element = ( <div> <h1 title="我是子h1元素屬性的內容">我是子h1元素的節點內容</h1> <h2>歡迎關注微信itclanCoder公眾號</h2> <h3>川川是全宇宙最帥的小夥子</h3> </div> )
包含在開始和結束標籤之間的 JSX 表達式內容將會被作為特定屬性 props.children
傳遞給外層組件
其中,有下面幾種不同的方法來傳遞子元素
**字元串字面量**
你可以將字元串放在開始和結束標籤之間,此時props.children
就只是該字元串,對於內置的HTML元素是很有用的,但同時要注意怎麼接收這個內容
<MyComponent>itclanCoder</MyComponent>
上面的JSX,MyComponent的子元素內容是itclanCoder,可以通過props.children
來獲取,它是一個沒有轉移的字元串itclanCoder
JSX會移除首尾行以及空行,與標籤相鄰的空行都會被刪除,文本字元串之間的新航都會被壓縮一個空格
所以下面的這幾種寫法都是等價的
<div>itclanCoder</div> <div> itclanCode </div> <div> 川川 itclanCode </div> <div> itclanCode </div>
**JSX子元素嵌套**
在React中,子元素允許由多個JSX元素組成,組件可以嵌套組件,例如:如下所示
<MyContainer> <Header /> <Navigator /> <Aside /> <Footer /> </MyContainer>
在React中,是可以將不同類型的子元素混合在一起的,這跟在以前寫HTML是一樣的
<div> 七月的天好熱 <ul> <li>item1</li> <li>item2</li> <li>item3</li> </ul> </div>
在React組件中,render函數的return的返回值,可以返回一個數組,例如:
render() { // return 後面是一個數組 return [ <div key="div1">div1</div>, <div key="div2">div2</div>, <div key='div3'>div3</div> ] } // 當然為了更好的看得舒服些的,最好是定義一個變數的 render() { var aDiv = [ <div key="div1">div1</div>, <div key="div2">div2</div>, <div key='div3'>div3</div> ] return aDiv; }
**javascript表達式作為子元素**
在插值表達式中,javascript表達式可以被包裹在雙大括弧{}
中,以下兩種寫法都是等價的
<myComponent>川川</myComponent> <myComponent>{'川川'}</myComponent>
至於這種寫法的具體實用:對於展示任意長度的列表就非常有用了的,渲染HTML列表
import React from 'react'; import ReactDOM from 'react-dom'; class Item extends React.Component { constructor(props) { super(props); } render() { return ( <ul> <li>{ this.props.message }</li> </ul> ); } } class TodoLIst extends React.Component { constructor(props) { super(props); this.todos = ['起床', '刷牙', '洗臉', '工作']; } render() { return ( <div> { this.todos.map((message) => <Item key = {message} message = { message } />) } </div> ); } } const container = document.getElementById('root'); ReactDOM.render(<TodoLIst />, container);
效果如下所示

**函數作為子元素**
{}
插值表達式內可以可以變數,字元串,普通HTML元素,甚至可以是組件,還可以是函數
import React from 'react'; // 引入react.js,通過import關鍵字實例化一個React對象 import ReactDOM from 'react-dom'; import { tsPropertySignature } from '@babel/types'; function Repeat(props){ let items = []; for(let i = 0; i < props.numTimes; i++) { items.push(props.children(i)); } return <div>{ items }</div> } function ListOfTenFun() { return ( <Repeat numTimes={ 10 }> { (index) => <div key={index}>我是列表 { index }</div> } </Repeat> ) } const container = document.getElementById('root'); ReactDOM.render(<ListOfTenFun />, container);
效果如下所示:

上面使用的是兩個函數組件,組件裡面是可以嵌套另一組件的,並且屬性值可以通過props拿到
也說明了,你是可以將任何東西作為子元素傳遞給自定義的組件的,
只要該組件渲染之前能夠被轉換成React理解的對象,它可以用於拓展JSX
自定義的組件必須是大寫字母開頭
通常來說,如果在React中小寫字母開頭的html標籤,稱為普通元素,它是原生HTML內置的元素(也可以視為為組件),例如:<div>``<span>``<a>
會被React轉化生成相應的字元串'div'
,'span'
傳遞給React.createElement
作為參數
大寫字母開頭的元素,我們將它視為自定義的組件,例如<MyButton />
,其實它最終也會被React.createElement函數作為轉化
使用大寫字母開頭命名自定義組件,這是一種約定俗成的規定,本質上它就是一構造函數,是為了區別普通函數的
JSX標籤的第一部分指定了React元素的類型
凡是大寫字母開頭的JSX標籤元素,就意味著它們是React組件
如果你定義的一個組件首字母是小寫,react就會當做一個普通元素來處理,而原生HTML標籤並沒有把你自定義的元素歸納進去,它是會報錯的
例如:如下所示
import React from 'react'; import ReactDOM from 'react-dom'; import { tsPropertySignature } from '@babel/types'; // 以下是定義的函數組件,首字母小寫,這個是不正確的 function button(props) { return ( <div> <button>{ props.content }</button> </div> ) } function OutButton(){ return ( <Button content="按鈕" /> ); } const container = document.getElementById('root'); ReactDOM.render(<OutButton />, container); // 正確的寫法 function Button(props) { return ( <div> <button>{ props.content }</button> </div> ) } ReactDOM.render(<OutButton />, container);
雖然錯誤的寫法不會報錯,它會將button
認為是一個html普通的標籤元素.
**注意**:
React必須在作用域內,JSX其實就是React.createElement函數的語法糖,React.createElement是更接近底層的API,所以React庫也必須包含在JSX程式碼作用域內
引入React庫一部分目的就是為了識別JSX語法的,這也是為什麼只要你定義一個React組件時,要引入React庫的原因
使用點(.)語法
有時候,在一個模組中需要導出多個React組件時,在JSX中,使用點語法來引用一個React組件就非常方便了的
例如:如下所示
import React, { Fragment, Component } from 'react'; import ReactDOM from 'react-dom'; // MyButton組件 class MyButton extends Component { constructor(props){ super(props); } render() { return ( <Fragment> <button>{ this.props.btnContent }</button> </Fragment> ); } } // MyInput組件 class MyInput extends Component{ constructor(props) { super(props); } render() { return ( <Fragment> <input value = { this.props.inputValue } /> </Fragment> ); } } // 搜索部分 class SearchArea extends Component { render() { return ( <Fragment> <FormComponent.MyInput inputValue="我是input組件輸入框內容" /> <FormComponent.MyButton btnContent="搜索按鈕" /> </Fragment> ); } } let FormComponent = { MyButton: MyButton, MyInput: MyInput } // 或者下面是Es6的一種等價寫法 let FormComponent = { MyButton, MyInput } const container = document.getElementById('root'); ReactDOM.render(<SearchArea />, container);
最終結果如下圖所示:

上面是把頁面中的某一個模組(搜索),把與之相關的組件集中放在一個對象下管理,當然在實際開發中,因人而異了,要是看到別人這麼寫,也不要覺得怪怪的.
拓展運算符,屬性展開
對於拓展運算符(…),是一個非常有用的語法,如果你已經有了一個props對象,你可以使用展開運算符...
在JSX中傳遞整個props對象
如下所示:
function PersonA() { return ( <Info name="川川" age="一個靠前排的90後帥小伙" /> ); } // 上面的return後面的等價於 function personA() { const props = { name: "川川", age:"一個靠前排的90後帥小伙"} return ( <Info { ...props } /> ); } function Info(props){ return ( <div>{ props.name }--{ props.age }</div> ); } const container = document.getElementById('root'); ReactDOM.render(<PersonA />, container);
**小tips:如何將一對象進行輸出?**
對於數組對象,可以通過map方法進行輸出,然而假如是對象的話,卻是沒有這個方法的
具體使用的是Object.keys(對象)這個方法,它會返回一個數組,並且將對象的屬性名保存在一個數組中,如果是要獲取對象的屬性值,則可以先轉數組,然後在使用數組的一些方法:例如map方法進行處理一下
var obj = { name: "川川", age: "你猜,小鮮肉一枚" } var getAttr = Object.keys(obj); var getValue = Object.keys(obj).map((item) => obj[item]); console.log(getAttr); // ["name", "age"] console.log(getValue);// ["川川", "你猜,小鮮肉一枚"]
如下真實例子如下所示
import React, { Fragment, Component } from 'react'; import ReactDOM from 'react-dom'; class List extends Component { constructor(props) { super(props); // 下面是為簡化程式碼,綁定this this.content = this.props.content; this.value = this.props.value; } render() { return ( <Fragment> <ul> { <li>{ this.content }-- { this.value }</li> } </ul> </Fragment> ); } } class Person extends Component { constructor(props) { super(props); this.person = { name: "川川", age: "一個靠前排的90後帥小伙", desc: "歡迎關注微信itclanCoder公眾號" } } render() { let getPerson = Object.keys(this.person); return ( <Fragment> { getPerson.map((item) => <List key = { item } content = { item } value = { this.person[item]} /> ) } </Fragment> ); } } const container = document.getElementById('root'); ReactDOM.render(<Person />, container);
最終的效果如下所示:

JSX中的props
自定義組件定義的屬性稱為prop,而屬性值稱為prop值,由於組件可以定義多個屬性,所以可以由多種方式在JSX中指定props
由於JSX會被轉換為React.createElement(組件元素, 屬性對象, 子元素),例如:如下JSX
const info = { title:"我是一個組件", number: 20 } // 將info對象存儲到infoMessage變數屬性中,並傳給MyComponent組件 <MyComponent infoMessage = { info }>my component</MyComponent> // 最終會被轉化為 React.createElement(MyComponent, { infoMessage: info}, 'my component')
調用組件處,被稱為父組件,而定義組件處,被稱為子組件,對應的子組件想要接收父組件的值,用props
去接收
label中的htmlFo
在原生html標籤中label與input的結合使用,增大滑鼠的觸控範圍,起到增強用戶體驗的作用
for
在JSX中應該被寫作htmlFor
<label htmlFor="firstname">First name:</label> <input type="text" name="firstname" id="firstname">
結果如下所示

總結
本文主要講述在JSX中添加屬性的命名方式應是camelCase駝峰式命名來定義屬性的名稱,JSX中的子元素可以是字元串,可以嵌套,以及js表達式,函數都可以作為子元素
並且在React中組件的定義以及調用處,組件名稱首字母必須要大寫,當導出多個React組件時,使用點語法來引用一個React組件
使用展開運算符 …在JSX中傳遞整個props對象
某些時候,是一個非常有用的語法,另外,當遍歷要渲染的是一對象時,對象並沒有數組的一些方法,通過Object.keys()進行轉換,然後在使用.能夠得到對象的屬性以及屬性值
也知道JSX中的何為prop,以及怎麼去接收props值
對於label與input使用時,要注意的一些地方.
當然對於JSX的相關知識學習暫且就這麼多了,仍然還有很多東西要學習的,編程是一門不斷探索的藝術,希望分享的這些的這些對你有些用