React學習(3)-不可不知的JSX

  • 2019 年 10 月 4 日
  • 筆記

前言

本篇內容,對上一節的補充

  1. JSX中添加屬性有什麼要注意的?以及JSX中的子元素是怎麼操作的?
  2. 組件的大小寫問題,使用拓展運算符,以及怎麼循壞遍歷一個對象
  3. JSX中的prop指的是什麼?以及表單的labe應該要注意什麼?

以上問題即使自己很清楚,但是否有時卻總是道不清,說不明?那麼讀完本文,就豁然開朗了

如果你想閱讀體驗更好,可戳鏈接,不可不知的JSX,內有視頻

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);

效果如下所示

javascript作為表達式

**函數作為子元素**

{}插值表達式內可以可以變量,字符串,普通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的相關知識學習暫且就這麼多了,仍然還有很多東西要學習的,編程是一門不斷探索的藝術,希望分享的這些的這些對你有些用