React基礎(2)-深刻淺出JSX

前言

在Jq,原生javascript時期,在寫頁面時,每每強調的是內容結構,層疊樣式,行爲動做要分離,三者之間分工明確,不要耦合在一塊兒javascript

然而在React出現後,一切皆js,對於在JS裏面寫HTML代碼,剛開始是很是反感的,甚至有違背當初的原則前端

可是,對於原先那種僅僅是把三種語言技術放在了三種不一樣文件位置裏進行分開管理了,實際上,它並無實現邏輯上的分離java

既然前端UI顯示就是HTML,CSS,javascript,那麼把實現一個功能的全部代碼放在一個文件裏管理,也是一種宏觀上代碼的封裝,模塊化處理.react

使用JSX並非倒退,它只是一個語法糖而已,雖然在React中,不強制要求使用JSX,可是官方卻推薦使用.android

由於在javascript代碼中將JSX和UI放在一塊兒在視覺上有輔助做用,另外,它還可使React顯示跟過有用的錯誤和警告信息數組

下面就一塊兒來學習下JSX吧,當你習慣它以後呢,並不會嗤之以鼻,反而會引覺得愛的!瀏覽器

正文從這裏開始~微信

JSX是什麼?

全稱: javascript and XMLbabel

定義: 可拓展(自定義)標記性語言,基於javascript,融入了XML,咱們能夠在js中書寫xml,使用JSX能夠很好的描述UI在頁面中應該呈現它應有的交互形式cookie

相似下面的這種,非官方提供的普通標籤,而是本身定義具備必定含義的特殊標籤

<person>
  <name></name>
  <age></age>
  <height></height>
  <weight></weight>
</person>

其實,你可把這些自定義的標籤,稱爲組件,頁面中的某一部分,具備獨立的功能和邏輯. 實現組件化的好處,不言而喻,下面來看看React的JSX是怎麼樣的

當你用create-react-app腳手架,初始化一個react應用後,在入口文件index.js中最後一行代碼,ReactDOM.render()函數調用的第一個實參數的寫法<App />

import React from 'react'; // 引入react.js庫,並用import關鍵字定義實例化了一個React對象
import ReactDOM from 'react-dom'; // 引入react-dom.js,同上,實例化了ReactDOM對象

ReactDOM.render(<App />, document.getElementById('root')) // 將App組件經過ReactDOM.render()函數,掛載到root根節點上,插入到頁面中去

爲了更好的理解,你能夠在index.js中,將代碼更改爲以下

const element = <App />;
const container = documnent.getElementById("root");

ReactDOM.render(element, container);

其中ReactDOM是react-dom的一個實例對象,它是用來將虛擬dom轉換爲真實DOM的,ReactDOM實例化對象下的一個render方法,接收兩個實際參數,第一個實參數,是要渲染的組件,第二個實參數,是該組件的掛載點,將該組件渲染到什麼位置上,上面是渲染到根節點root上

ReactDOM.render(要渲染的組件, 組件要掛載的位置);

其中相似這種JSX:

const element = <h1 title="h1標籤">Hello,itclanCoder</h1>
// 等價於
var element = React.createElement('h1',{title:"h1標籤"}, "hello, itclanCoder" );
// React.createElement() 會預先執行一些檢查,以幫助你建立了這麼一個對象,可是在實際中不要這麼寫,它是會報錯的
var element = {
   type: 'h1',
   props: {
   title: "h1標籤",
   children: "hello,itclanCoder"
  }
}

這些對象被稱爲 「React 元素」。它們描述了你但願在屏幕上看到的內容。React經過讀取這些對象,而後使用它們來構建 DOM 以及保持隨時更新

注意:

  • React中並無模板語言(相似Vue的template的),可是它具備JavaScript的所有的功能
  • 能夠在JS中書寫XML(HTML) 只能有且僅有一個頂層元素 ,固然也能夠藉助React提供的Fragment(也叫佔位符)這個內置組件將你寫的JSX子元素給包裹起來,能夠包含子節點 ,也支持插值表達式 {表達式}
  • 爲了便於閱讀,return返回的jsx內容,用一個圓括號()包裹起來,這樣能夠將JSX拆分爲多行。這樣作不是強制要求的,可是這能夠避免遇到自動插入分號陷阱

以下代碼所示:

import React from "react";
import ReactDOM from "react-dom";


class Acomponent extends React.Component {
    render() {
// return 後面帶着一個圓括號,只是爲了換行顯示,根節點最頂層只能是一個元素
      return (
       <div>
         <h1 title="我是川川">一個靠前排的90後帥小夥</h1>
         <h2>歡迎關注微信itclanCoder公衆號</h2>
       </div>
       )
     }
}

// 或者使用React提供的Fragement佔位符組件也能夠,可是先引入
import React, { Componnet, Fragment } from "react";
import ReactDOM from "react-dom";

class Acomponent extends Component {
  render() {
    return (
     <Fragment>
        <h1 title="我是川川">一個靠前排的90後帥小夥</h1>
        <h2>歡迎關注微信itclanCoder公衆號</h2>
     </Fragment>
    )
   }
}

下面來具體來看看JSX是如何使用的

JSX的具體使用

  • 在JSX中嵌入表達式{ 表達式 }

雙大括號內能夠是變量,字符串,數組,函數調用, 可是不能夠是對象,也不支持 if,for語句

例如:你在插值表達式裏寫對象:它是會報錯的

{ {name: "川川", age: "一個靠前排的90後帥小夥"} }

錯誤以下所示:

Objects are not valid as a React child (found: object with keys {name, age}). If you meant to render a collection of children, use an array instead

該錯誤的意思是:對象無效做爲React子對象(找到:具備鍵{name,age}的對象)。若是您要渲染子集合,請使用數組

固然若是是數組的話,它會自動的給拼接起來,本質上是經過數組中的join("")方法處理後的結果

{ ["川川", "全宇宙最帥"]} //川川全宇宙最帥

固然對於在JSX裏面寫if,for語句也是會報錯的

<li>
 {
   if(this.isBtn) { <Button />
 }
</li>

其實,JSX 也是一個表達式,它雖然不支持if,for語句,可是它在if,for循環的代碼塊中是可使用JSX的,將JSX賦值給變量,把JSX看成參數傳入,以及從函數中返回JSX

function getMessage(user) {
  if (user) {
    return <h1>Hello, { formatName(user) }!</h1>;
  }
  return <h1>Hello, itClanCoder.</h1>;
}

注意:布爾類型、Null 以及 Undefined 將會被忽略,false, null, undefined, true是合法的子元素。但它們並不會被渲染。如下的 JSX 表達式渲染結果都是相同的

<div />

<div></div>

<div>{ false }</div>

<div>{ null }</div>

<div>{ undefined }</div>

<div>{ true }</div>

具體做用: 這有助於在特定條件來渲染其餘的 React 元素。例如,在如下 JSX 中,僅當 isBtn 爲 true 時,纔會渲染 <Button />

<div>
  { isBtn && <Button /> }
  <Content />
</div>

有一點須要注意的是:有一些false值,例如:數字0,仍然會被React渲染,例如:以下所示

<div>
{
  this.aBtns.length &&
  <Button content="我是按鈕" />
}
</div>

要解決這個問題,確保 && 以前的表達式老是布爾值,就能夠了

反之,若是你想渲染 false、true、null、undefined 等值,你須要先將它們轉換爲字符串:

轉換字符串有以下三種方法

  • 對象.toString(),注意此方法,針對數據類型是null對象,及undefined,不適用
  • 用空字符串拼接:variable+'';此方法比較廣泛,可是可讀性有些差
  • String(variable):用String字符串對象方法進行轉化,推薦使用
<div>
  <p>對象.toString(){ myVariable.toString() }</p>
  <p>用空字符串拼接{ myVariable + '' }</p>
  <p>用String(variable){ String(myVariable) }</p>
</div>

固然,插值表達式中變量也能夠用Es6中的反引號

hello, { `${String(false)}` } // false

介紹了那麼多,依然仍是不夠的,下面來看看JSX的原理,理解了這個,你將會知道一個JSX到底是怎麼工做,以及怎麼渲染到頁面上去的

JSX原理

頁面中的DOM元素結構均可以用javascript對象來描述,包括的信息有,標籤名,屬性,子元素,事件對象

在JS裏面,一切皆對象,對象的特色就是,含有屬性或者方法,,其實任何東西,均可以用對象去描述

例如:以下的JSX結構

<div class="input-wrap">
  <input 
     type="text" 
     autocomplete="off" 
     value="" 
     id="mq" 
     class="input" 
     title="請輸入搜索文字" />
  <button>搜索</button>
</div>

假如用對象來描述一下上面的信息

{
  tagName: 'div',
  attribute: { className: 'input-wrap'},
  children: [
   {
     tagName: 'input',
     attribute: {
       type: "text",
       autocomplete:"off",
       value:"",
       id:"mq",
       class:"input",
       title:"請輸入搜索文字"
      }
  },
  {
   tagName: "button",
   attribute: null,
   children: '搜索'
  }
]
}

當直接把這個HTML段代碼寫在React中,它背後實際上是經過React.createElement()方法進行建立的,建立相似這樣的

{
  type: 'div',
  props: {className: 'input-wrap' },
  children: [
   {
     type: 'input',
     props: { 
         type:'text', 
         autocomplete:"off", 
         value:"",id:"mq", 
         class:"input", 
         title:"請輸入搜索文字"
     },
     {
        type: 'button',
        props: null,
        children: '搜索'
     }
  ]

}

你能夠聯想一下原生javascript的document.createElement()與JQ中的$("")建立一個js對象與jQ對象的,而在React中,React就是一個實例化對象,更深層次探討的話,React也是基於原型對象構建出來的

儘管React與前二者不一樣,可是筆者仍然以爲有相似,殊途同歸之妙,例如React下面的createElement方法,仍然與原生document文檔對象下面的建立元素方法相同

若是原生javascript紮實的話,便不難理解React在這作了一層轉化
既然js對象描述的UI(DOM)信息與HTML所展現的結構信息是同樣的,那爲何不用Js對象來代替呢,由於用對象字面量寫的方式太繁瑣了,又臭又長的,結構又不清晰,若是用HTML來展現UI信息,那麼就簡單多了

React.js 就把js語法擴展了一下,讓 Js語言可以支持這種直接在Js代碼裏面編寫相似 HTML 標籤結構的語法,這樣寫起來就方便不少了。編譯的過程會把相似 HTML 的 JSX 結構轉換成 JavaScript 的對象結構

上面的代碼:

import React from 'react'
import ReactDOM from 'react-dom'

class Search extends React.Component {
render () {
  return (
   <div class="input-wrap">
     <input 
        type="text" 
        autocomplete="off" 
        value="" 
        id="mq" 
        class="input" 
        title="請輸入搜索文字" />
     <button>搜索</button>
   </div>
  )
 }
}

ReactDOM.render(
<Search />,
document.getElementById('root')
)

通過babel編譯,Babel 會把 JSX 轉譯成一個名爲 React.createElement() 函數調用

以下所示

import React from 'react'
import ReactDOM from 'react-dom'

class Search extends React.Component {
   render () {
     return (
       React.createElement(
        "div",
        {className: 'input-wrap'},
       React.createElement(
         "input",
         { type:'text',
           autocomplete:"off",
           value:"",
           id:"mq",
           class:"input",
           title:"請輸入搜索文字" 
         }
     ),
     React.createElement(
       'button',
       null,
       "搜索"
      )

    )
  )
 }
}

ReactDOM.render(
React.createElement(Search, null),
document.getElementById('root')
);

換言之,若是你自定義的一個組件:例如:<ElButton bgColor="green">綠色按鈕</ElButton>

import React from 'react';
import ReactDOM from 'react-dom'


class ElButton extends React.Component {
    constructor(props){
      super(props);
    }
   render() {
     return (
       <button 
          style={ {color: this.props.bgColor} }>{ this.props.children }</button>
      )
}
}


ReactDOM.render(<ElButton bgColor="green">綠色按鈕</ElButton>, document.getElementById('roo

通過Babel的轉化後

React.createElement(
  ElButton,
  { bgColor: green},
  children: "綠色按鈕"
)

最終渲染到瀏覽器上,結果以下所示

在編譯以後,JSX 表達式會被轉爲普通 JavaScript 函數調用,而且對其取值後獲得 JavaScript 對象

React.createELmenet會構建一個js對象來描述你的HTML結構信息,包括標籤名,屬性,子元素以及事件對象等

使用React必定要引入React庫,引入這個是爲了解析識別JSX語法糖(React.createElement()函數的替代)

固然另外一方面也是爲了建立虛擬DOM(所謂虛擬DOM,它就是一個JS對象,是用它來描述真實的DOM,上面的例子,已經很明白了)

而引入react-dom的緣由就是,爲了將虛擬DOM轉換爲真實DOM,而後把這個DOM元素插入到頁面中,這正是ReactDOM.render()作的事情,把組件渲染而且構造 DOM 樹,而後插入到頁面上某個特定的元素上

因此在你編寫一個組件的時候,一開始就要引入react.js和react-dom這兩個文件的

當使用JSX到最終展示頁面結構到瀏覽器上:經歷了以下過程:若是你在代碼中進行斷言一下,就很是清晰這一過程了


因此概括一下:JSX其實就是javascript對象,是用來描述UI結構信息的,JSX語法並非真實的DOM, 使用JSX是爲了方便開發人員寫代碼更簡單,簡潔

固然實際開發中,咱們並不會去用React.createElement()去建立元素,不是說它不能完成需求,只是由於它寫起來比較雞肋,代碼維護起來很是麻煩,可讀性差

相比於寫JS,寫HTML仍是比較容易吧,但也是不簡單的哦,由於寫JS比較燒腦,容易掉頭髮呀,HTML自己是不具有邏輯可言的

然而,到手的人民幣的高低,更多的是取決於你的JS水平...,這個的確是滴,JS水平高,真的是能夠直接喊高價的

小結

JSX 是 JavaScript 語言的一種語法擴展,長得像 HTML,但並非 HTML,附加了原生HTML標籤不具有的能力,例如:自定義屬性,以及後續的組件傳值

UI界面顯示什麼樣,取決於JSX對象結構,換句話說,取決於render()函數裏面的return關鍵字後面返回的JSX結構

引入React.js庫是爲了解析識別JSX語法,同時建立虛擬DOM,而引入react-dom是爲了渲染組件,將組件掛載到特定的位置上,同時將虛擬DOM轉換爲真實DOM,插入到頁面中

總結

本文主要講述了JSX是什麼?以及JSX的一些注意事項,JSX的具體使用,嵌入表達式,最重要的是JSX的原理,在使用JSX中,react是如何將jsx語法糖裝換爲真實DOM,並渲染到頁面中的,固然,JSX仍然還有一些注意事項,邊邊角角的知識的,限於篇幅,貪多嚼不爛,咱們下次再繼續了

若是你想要閱讀體驗更好,能夠點擊該連接

相關文章
相關標籤/搜索