React基礎——JSX語法

JSX是React的核心組成部分,它使用XML標記的方式去直接聲明界面,界面組件之間可以互相嵌套。可以理解為在JS中編寫與XML類似的語言,一種定義帶屬性樹結構(DOM結構)的語法,它的目的不是要在瀏覽器或者引擎中實現,它的目的是通過各種編譯器將這些標記編譯成標準的JS語言。

雖然你可以完全不使用JSX語法,只使用JS語法,但還是推薦使用JSX,可以定義包含屬性的樹狀結構的語法,類似HTML標簽那樣的使用,而且更便于代碼的閱讀。

使用JSX語法后,你必須要引入babel的JSX解析器,把JSX轉化成JS語法,這個工作會由babel自動完成。同時引入babel后,你就可以使用新的es6語法,babel會幫你把es6語法轉化成es5語法,兼容更多的瀏覽器。

我們從最簡單的一個官網例子helloworld開始:

  <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8" />
      <title>Hello React!</title>
      <script src="vendor-js/react.js"></script>
      <script src="vendor-js/react-dom.js"></script>
      <script src="vendor-js/babel-core/browser.min.js"></script>
    </head>
    <body>
      <div id="example"></div>
      <script type="text/babel">
        ReactDOM.render(
          <h1>Hello, world!</h1>,
          document.getElementById('example')
        );
      </script>
    </body>
  </html>

在這個簡單的例子中,看不出來有任何jsx語法的地方,當其中<h1>Hello,world</h1>就是使用到了jsx語法。HTML 語言直接寫在 JavaScript 語言之中,不加任何引號,這就是 JSX 的語法,它允許 HTML 與 JavaScript 的混寫。如果轉化成純JavaScript 的話,就是:

    <script type="text/javascript">
      ReactDOM.render(
        React.DOM.h1(null,'hello,world!'),
        document.getElementById('example')
      );
    </script>

在上述JSX語法中有兩個要注意的地方:

  • <script> 標簽的 type 屬性為 text/babel,這是React 獨有的 JSX 語法,跟 JavaScript 不兼容。凡是在頁面中直接使用 JSX 的地方,都要加上 type="text/babel"。
  • 一共用了三個庫: react.js 、react-dom.js 和 browser.min.js ,它們必須首先加載。其中,react.js 是 React 的核心庫,react-dom.js 是提供與 DOM 相關的功能, browser.min.js的作用是將 JSX 語法轉為 JavaScript 語法。

將 JSX 語法轉為 JavaScript 語法,這一步很消耗時間。現在前端項目,都會使用前端工程化,不會直接在html頁面中直接寫js代碼,寫好的js代碼都會使用工具進行編譯壓縮等。這樣的話,我們的jsx也會通過編譯直接轉化成js語法,讓瀏覽器直接使用。

ReactDOM.render 是 React 的最基本方法,將模板轉為HTML語言,并插入指定的 DOM 節點。

JSX的特點:

  1. 類XML語法容易接受,結構清晰
  2. 增強JS語義
  3. 抽象程度高,屏蔽DOM操作,跨平臺
  4. 代碼模塊化

JSX基本語法規則:

JSX本身就和XML語法類似,可以定義屬性以及子元素。唯一特殊的是可以用大括號來加入JavaScript表達式。遇到 HTML 標簽(以 < 開頭),就用 HTML 規則解析;遇到代碼塊(以 { 開頭),就用 JavaScript 規則解析。

var arr = [
 <h1>Hello world!</h1>,
 <h2>React is awesome</h2>,
];
ReactDOM.render(
 <div>{arr}</div>,
 document.getElementById('example')
);

這個就是一個簡單的html與js混用的例子。arr變量中存在html元素,div中又使用了arr這個js變量。轉化成純javascript的話:

var h1=React.DOM.h1(null,'Hello world!');
var h2=React.DOM.h1(null,'React is awesome');
var div=React.DOM.div(null,h1,h2);
ReactDOM.render(
 div,
 document.getElementById('example')
);

React組件

我們使用jsx來將代碼封裝成React組件,然后像插入普通 HTML 標簽一樣,在其他地方插入這個組件。使用React.createClass用于生成一個組件。

var MyComponent=React.createClass({
  render: function() {
   return <h1>Hello world!</h1>;
 }
});
ReactDOM.render(
 <MyComponent />,
 document.getElementById('example')
);

上面代碼中,變量 MyComponent就是一個組件類。模板插入 <MyComponent /> 時,會自動生成 MyComponent 的一個實例(下文的"組件"都指組件類的實例)。所有組件類都必須有自己的 render 方法,用于輸出組件。

React 可以渲染 HTML 標簽 (strings) 或 React 組件 (classes)。

  • 在react中通常約定組件類的第一個字母必須大寫,html標簽都是小寫。

//要渲染 HTML 標簽,只需在 JSX 里使用小寫字母開頭的標簽名。
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.getElementById('example'));
//要渲染 React 組件,只需創建一個大寫字母開頭的本地變量。
var MyComponent = React.createClass({/.../});
var myElement = <MyComponent />;
React.render(myElement, document.getElementById('example'));

* 還有一個注意點:組件類只能包含一個頂層標簽,否則會報錯。
```javascript

//var myDivElement =<h1>你好</h1><h1>hello</h1>;
//上述寫法是會報錯的,要寫成只有一個頂層標簽:
var myDivElement =<div><h1>你好</h1><h1>hello</h1></div>;

上述代碼一個靜態的組件,下面看一個動態組件:

var MyComponent=React.createClass({
  getInitialState: function() {
       return {clickNum: 0};
  },
  handleClick:function(){
    var num=this.state.clickNum;
    num++;
    this.setState({clickNum:num});
  },
  render: function() {
   return (
      <div>
        <h1 onClick={this.handleClick}>Hello {this.props.name}!</h1>
        <h2 style={{color:'red'}}>點擊{this.props.name}次數:{this.state.clickNum}</h2>
      </div>
    );
 }
});
ReactDOM.render(
  <div>
     <MyComponent name="張三" />
     <hr/>
     <MyComponent name="李四" />
  </div>,
 document.getElementById('example')
);

上面代碼中定義的MyComponent組件包含屬性,狀態和事件,是一個簡單的比較完整的組件。使用props通過父組件進行傳遞值,使用state定義組件自己的狀態,組件支持的大部分的DOM操作事件。

關于屬性props:

  • class 屬性需要寫成 className ,for 屬性需要寫成 htmlFor ,這是因為 class 和 for 是 JavaScript 的保留字。
  • 直接在標簽上使用style屬性時,要寫成style={{}}是兩個大括號,外層大括號是告知jsx這里是js語法,和真實DOM不同的是,屬性值不能是字符串而必須為對象,需要注意的是屬性名同樣需要駝峰命名法。即margin-top要寫成marginTop。
  • this.props.children 不要children作為把對象的屬性名。因為this.props.children獲取的該標簽下的所有子標簽。this.props.children 的值有三種可能:如果當前組件沒有子節點,它就是 undefined ;如果有一個子節點,數據類型是 object ;如果有多個子節點,數據類型就是 array 。所以,處理 this.props.children 的時候要小心。官方建議使用React.Children.map來遍歷子節點,而不用擔心數據類型。

關于狀態state:

  • 組件免不了要與用戶互動,React 將組件看成是一個狀態機,一開始有一個初始狀態,然后用戶互動,導致狀態變化,從而觸發重新渲染 UI。
  • getInitialState 方法用于定義初始狀態,也就是一個對象,這個對象可以通過 this.state 屬性讀取。當用戶點擊組件,導致狀態變化,this.setState 方法就修改狀態值,每次修改以后,自動調用 this.render 方法,再次渲染組件。

由于 this.props 和 this.state 都用于描述組件的特性,可能會產生混淆。一個簡單的區分方法是,this.props 表示那些一旦定義,就不再改變的特性,而 this.state 是會隨著用戶互動而產生變化的特性。

注意點:
如果往原生 HTML 元素里傳入 HTML 規范里不存在的屬性,React 不會顯示它們。如果需要使用自定義屬性,要加 data- 前綴。

<div data-custom-attribute="foo" />

PropTypes

組件的屬性props可以接受任意值,字符串、對象、函數等等都可以。有時,我們需要一種機制,驗證別人使用組件時,提供的參數是否符合要求。React中使用PropTypes進行參數的校驗。

var MyTitle = React.createClass({
   propTypes: {
     title: React.PropTypes.string.isRequired,
   },
   render: function() {
     return <h1> {this.props.title} </h1>;
   }
});

上面的Mytitle組件有一個title屬性。PropTypes 告訴 React,這個 title 屬性是必須的,而且它的值必須是字符串。當我們給title傳遞一個數字時,控制臺就會報錯:

Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.

此外,getDefaultProps 方法可以用來設置組件屬性的默認值。

獲取真實的DOM節點

組件并不是真實的 DOM 節點,而是存在于內存之中的一種數據結構,叫做虛擬 DOM (virtual DOM)。只有當它插入文檔以后,才會變成真實的 DOM 。
有時需要從組件獲取真實 DOM 的節點,這時就要用到 ref 屬性。

var MyComponent = React.createClass({
   handleClick: function() {
     this.refs.myTextInput.focus();
   },
   render: function() {
     return (
     <div>
       <input type="text" ref="myTextInput" />
       <input type="button" value="Focus the text input" onClick={this.handleClick} />
     </div>
     );
   }
});

為了獲取真是DOM節點,html元素必須有一個 ref 屬性,然后 this.refs.[refName] 就會返回這個真實的 DOM 節點。需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實 DOM ,所以必須等到虛擬 DOM 插入文檔以后,才能使用這個屬性,否則會報錯。

求值表達式

要使用 JavaScript 表達式作為屬性值,只需把這個表達式用一對大括號 ( { } ) 包起來,不要用引號 ( " " )。
在編寫JSX時,在 { } 中不能使用語句(if語句、for語句等等),但可以使用求值表達式,這本身與JSX沒有多大關系,是JS中的特性,它是會返回值的表達式。我們不能直接使用語句,但可以把語句包裹在函數求值表達式中運用。

條件判斷的寫法

你沒法在JSX中使用 if-else 語句,因為 JSX 只是函數調用和對象創建的語法糖。在 { } 中使用,是不合法的JS代碼,不過可以采用三元操作表達式

var HelloMessage = React.createClass({ 
  render: function() { 
    return <div>Hello {this.props.name ? this.props.name : "World"}</div>; 
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

可以使用比較運算符“ || ”來書寫,如果左邊的值為真,則直接返回左邊的值,否則返回右邊的值,與if的效果相同。

var HelloMessage = React.createClass({ 
  render: function() { 
    return <div>Hello {this.props.name || "World"}</div>; 
  }
});
函數表達式

( )有強制運算的作用

var HelloMessage = React.createClass({ 
  render: function() { 
    return <div>Hello { 
    (function(obj){ 
        if(obj.props.name) 
          return obj.props.name 
        else 
          return "World" 
      }(this)) 
    }</div>; 
  }
});
ReactDOM.render(<HelloMessage name="xiaowang" />, document.body);

外括號“ )”放在外面和里面都可以執行。唯一的區別是括號放里面執行完畢拿到的是函數的引用,然后再調用“function(){}(this)()”;括號放在外面的時候拿到的事返回值。

組件的生命周期

組件的生命周期分成三個狀態:

* Mounting:已插入真實 DOM
* Updating:正在被重新渲染
* Unmounting:已移出真實 DOM

React 為每個狀態都提供了兩種處理函數,will 函數在進入狀態之前調用,did 函數在進入狀態之后調用,三種狀態共計五種處理函數。

* componentWillMount()
* componentDidMount()
* componentWillUpdate(object nextProps, object nextState)
* componentDidUpdate(object prevProps, object prevState)
* componentWillUnmount()

此外,React 還提供兩種特殊狀態的處理函數。

* componentWillReceiveProps(object nextProps):已加載組件收到新的參數時調用
* shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調用

注釋

JSX 里添加注釋很容易;它們只是 JS 表達式而已。你只需要在一個標簽的子節點內(非最外層)小心地用 {} 包圍要注釋的部分。

{/* 一般注釋, 用 {} 包圍 */}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 40、React 什么是React?React 是一個用于構建用戶界面的框架(采用的是MVC模式):集中處理VIE...
    萌妹撒閱讀 1,038評論 0 1
  • React簡介 (1)簡介 React 起源于 Facebook 的內部項目,因為該公司對市場上所有 JavaSc...
    魚魚吃貓貓閱讀 1,658評論 1 6
  • 1、什么是react React.js 是一個幫助你構建頁面 UI 的庫。React.js 將幫助我們將界面分成了...
    谷子多閱讀 2,566評論 1 13
  • HTML模版 之后出現的React代碼嵌套入模版中。 1. Hello world 這段代碼將一個一級標題插入到指...
    ryanho84閱讀 6,272評論 0 9
  • 原教程內容詳見精益 React 學習指南,這只是我在學習過程中的一些閱讀筆記,個人覺得該教程講解深入淺出,比目前大...
    leonaxiong閱讀 2,854評論 1 18