React入門 (1)—使用指南(包括ES5和ES6對比)


前言

  本篇會簡明扼要的介紹一下React的使用方法。代碼會用JSX+ES5和JSX+ES6兩種方式實現。  

React簡介

  React來自Facebook,於2013年開源。至今不斷修改完善,現在已經到達了版本0.14.2。可以注意到版本還沒有到1.0, 普遍應用到大部分產品中還需要一定的時間。2015年3月份,FaceBook發布了React Native,一個用react來構建native app的框架。
  步入正題,React是一個javascript的類庫,用於構建用戶界面。

三個特點

  • JUST THE UI
      不同於Angularjs框架,React不屬於MVC框架,它可以算是MVC里面的V層,所以相對來說入門也簡單一下(只指入門,深度研究的話也不簡單)。

  • VIRTUAL DOM——虛擬DOM
      虛擬dom其實是輕量的js對象,只保留了原生dom的一些常用的屬性和方法。

    • 自定義標簽
        學習React需要有一種全新的思路去看待view層的構建。除了使用html原生的標簽,開發者還可以自定義標簽(即虛擬DOM,最終給瀏覽器渲染的時候會解析成原生dom),自然代碼解耦的效果會很明顯,也更易讀。
    • 性能提升
        在大家優化代碼性能的時候,一定會關注有沒有多余的dom操作,這是因為dom相關的操作耗時比較長。就算是創建一個空標簽,也許要初始化它的各種默認屬性和事件。
        React渲染頁面並不直接操作dom,而是先通過diff算法比較前后虛擬dom的差異。這最大程度的簡化dom操作,大大提高了性能。由於只是局部更新dom,所以只是局部刷新。
        換而言之,虛擬dom的出現,是因為目前js的性能比DOM渲染的性能要好,所以可以用更多的js操作換取更少的dom操作。也不排除如果將來有一天dom的性能和js差不多的時候,虛擬dom也許就沒那么大的意義了。
  • DATA FLOW
    React是單向響應的數據流。

React相關知識簡介

jsx

  一種特殊的js語法,可以在js代碼中直接使用html標簽。是個語法糖,提高編寫代碼效率。
  要注意不能在標簽的中間添加注釋,因為最終還是要翻譯成原生js,標簽中添加注釋相當於在一行代碼還沒完的時候就添加注釋。
  在jsx中,變量用花括號包圍起來,花括號內的語句將以js代碼的方式解析。
  例如:

// 用純js在react中創建a標簽
var newDom=<React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!');
// 用jsx在react中創建a標簽
var newDom=<a href="https://facebook.github.io/react/">Hello!</a>;

  要讓瀏覽器認識這種新的語法,就需要下面介紹的babel了。

babel

   是一個javascript代碼轉換器,在這里我們可以用於jsx轉換為原生js,es6轉換為es5(大部分都能轉換)。當然它的功能不只這些,有興趣的可以去babel官網看看。它還有個線上的轉換器,代碼比較簡單的時候用這個排查問題或練習es6很方便。
  介紹兩種常用的使用方式:

  • 一種是瀏覽器來編譯,因為實時編譯會很慢,所以適合代碼量比較小的。只需在html中引用:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  • 一種是本地使用。通過npm安裝,在webpack中配置:
//在webpack.config.js文件中配置
module.exports = {
	module: {
    	loaders: [{
      	test: /\.jsx?$/,
      	loader: 'babel'
    	}]
	}
}

  可以在本地編譯好代碼后,再將編譯后的代碼給html引用,提高性能,適合大項目。

webpack

  一個模塊打包工具,它把不同的、相互依賴的靜態資源都視作模塊,並且打包成我們想要的靜態資源。
  另外可以方便的配置多種預處理器,如babel。
  使用webpack,讓代碼組織更清晰,一個文件就是一個模塊。

ES6

  ES6,也叫ECMAScript2015(以下統稱ES6),是ECMAScript標准的最新版本。詳細可見ES6的特性簡述(譯+部分解析)

搭建簡單的運行環境

  • 方式一:直接引入react、reactdom、babel的庫。
      因為這種方式是瀏覽器負責即時編譯的,所以可想而知項目大了得時候解析速度會很慢,不建議使用。但是我們只是學習react語法嘛,當然要搭的環境越簡單越好。
      這種方式就是官網給出的實例所使用的方式。注意寫jsx的的js塊的type="text/babel",這樣才能被瀏覽器識別並用babel編譯。
      以下是本章要用到的代碼框架(一個helloword的demo) :
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>demo</title>
  </head>
  <body>
    <div id='example'></div>
    <script src="./build/react.js"></script>
    <script src="./build/react-dom.js"></script>
    <script src="./build/browser.min.js"></script>
    <script type="text/babel">
      // react代碼寫到這里
      ReactDOM.render(<h1>hello word!</h1>,document.getElementById('example'));
    </script>
  </body>
</html>
  • 方式二:使用npm + webpack
      篇幅限制,下篇說,歡迎看第二篇。

學會react的基本語法

  一般從定義到使用組件的流程是:定義組件creatClass,實現render方法->將組件渲染到頁面ReactDOM.render()。

創建ReactElement

  ReactElement對象可以看成是虛擬DOM樹。它既是渲染組件ReactDOM.render(root,container)的第一個參數,又是創建組件React.createClass中render方法的返回值。記住ReactElement是唯一父節點的’dom樹‘就好。

  • react原生實現
React.createElement(
  string/ReactClass type, //type組件類型可以是內置的標簽,如div;也可以是由React.createClass(object specification)創建的虛擬組件
  [object props], // 標簽屬性,數組
  [children ...],// 標簽的innerHtml
)//返回類型是ReactElement
var newDom=React.createElement('a', {href: 'https://facebook.github.io/react/'}, 'Hello!');
  • jsx實現
<a href=''>Hello</a>

把組件渲染到瀏覽器中

  react-dom模塊中的方法。
  ReactDom.render(root, container); root為ReactElement類型,表示root替換container中的元素。注意是替換不是追加,所以有些情況父元素應該設置為空。

  • react原生
var content=React.createElement('h1',{},'hello');
ReactDOM.render(content,document.getElementById('example'));
  • jsx
ReactDOM.render(<h1>hello word!</h1>,document.getElementById('example'));

創建組件

  組件是一個自定義的js對象,在es5中使用React.createClass();在es6中必須繼承React.component。
  其中有個特殊的render方法,返回ReactElement對象。該方法會在我們使用JSX語法的標簽 時被調用,因此我們在渲染組件時第一個參數可以使用 自定義標簽或者createElement。
  如:ReactDOM.render(<MyElement />,document.getElementById('example'))     

  • es5
var NewDom = React.createClass({//類名一定要大寫開頭
    render: function() {
        return (
            <ol>
              {
                React.Children.map(this.props.children, function (child) {
                  //獲得元素的子元素
                  console.info(this);
                  console.info('child:'+child);
                  return <li>{child}</li>;//變量用花括號標識
                })//因為有多個子元素,所以返回的是數組。按照JSX變量是數組來解析。
              }
            </ol>
       );
    }
});
ReactDOM.render(
    <NewDom>
        <span>lala</span>
        <span>ass</span>
    </NewDom>,
     document.getElementById('example')
);
  • es6
class NewDom extends React.Component{
    render() {//開頭花括號一定要和小括號隔一個空格,否則識別不出來
        return <ol>//標簽開頭一定要和return一行
          {
             React.Children.map(this.props.children, function (child) {
                   return <li>{child}</li>;
             })
          }
        </ol>;
    }
} 
ReactDOM.render(
    <NewDom>
        <span>lala</span>
        <span>ass</span>
    </NewDom>,
     document.getElementById('example')
);       

組件的屬性props

一個js對象,對應於dom的屬性。

  • 原生屬性
    某些html的屬性名因為正好是js得保留字,所以需要重新命名。
    • class
      因為js中class為保留字,所以要寫成className。
      <a className="center"></a>
    • style
      style屬性接受由css屬性構成的js對象。對於jsx來說第一是變量,第二是對象,因此要兩個花括號,key值用駝峰命名法轉化了,value值用引號括起來
      <a style={{backgroundImage: 'url(' + imgUrl + ')',font:'12px'}}></a>
  • 新增屬性
    this.props.children 表示組件的所有子節點,上一小節的示范代碼中有介紹
  • 傳遞屬性值
    在ReactDOM.Render第一個參數中直接寫入帶屬性的標簽即可: <a newProp="propValue"></a> 。這樣就可以在this.props['newProp']中讀取值
  • 設置默認屬性
    • 在ES6中為屬性:defaultProps(可以標識static定義在class內,也可以定義在class外)
    • 在ES5中為方法:getDefaultProps: function(){return {name:value}};
  • 屬性的讀取
    this.props['propName']獲得屬性
  • 新增功能:屬性校驗器propTypes
    見代碼示例
  • 代碼示范
    • es5
var NewDom = React.createClass({//類名一定要大寫開頭
    getDefaultProps: function() {//設置默認屬性
       return {title:'133'};
    },
    propTypes: {
       title:React.PropTypes.string,
    },//屬性校驗器,表示必須是string
    render: function() {
       return <div>{this.props.title}</div>;//變量用花括號標識
    }
});
  • es6
class NewDom extends React.Component{
  //不能再組件定義的時候定義一個屬性
  render() {
      return <div >1{this.props.title}</div>;
  }//開頭花括號一定要和小括號隔一個空格,否則識別不出來
}
//es6 這兩個屬性不能寫在class內。
NewDom.propTypes={//屬性校驗器,表示改屬性必須是bool,否則報錯
  title: React.PropTypes.bool,
}
NewDom.defaultProps={title:'133'};//設置默認屬性

組件的狀態state

  一個js對象,存儲着組件當前的狀態以及其值的集合。
  個人覺得這也是react的創新點之一,可以把組件看成一個“狀態機”. 根據不同的status有不同的UI展示。只要使用setState改變狀態值,根據diff算法算出來有差以后,就會執行ReactDom的render方法,重新渲染頁面。
  這避免了開發者直接操作dom對象已達到重新渲染頁面。開發者只需要關注state這個中間人,控制它就可以控制頁面刷新。第二篇中評論框的渲染就是使用的state來控制。
  是不是感覺和props有些類似?一般區分兩個的原則是,可變的放在state中,不可變的放在props中。 

  • 初始化
  • es5
class *** extends React.Component{
  getInitialState: function() {
    return {liked: false};
  }
}
  • es6
class *** extends React.Component{
   constructor(props) {
    super(props);
    this.state = {liked: false};
  }
}
  • 修改值
    es5和es6中使用方法相同。
    this.setState(新的state對象);
  • 讀取值
    其實就是讀取一個js對象。

事件

  • 事件名
    和屬性名類似,到了react中,事件名也成了駝峰命名法,比如onclick變為了onClick.

  • 事件定義
    一定要注意es6中元素如何使用自定義事件。見代碼。

    • es5
var NewDom = React.createClass({//類名一定要大寫開頭
    btnClick:function(ele){
       console.info(ele);
       console.info(this.refs.tex);
    },
    render: function() {
       return <div >
          <input type="text" ref="tex" />
          <input type="button" onClick={this.btnClick} value='click me' />
       </div>;//變量用花括號標識
    }
});
  • es6
class NewDom extends React.Component{
    btnClick(){
        console.info(this);//this為該組件類
        console.info(this.refs.tex);//this.refs.tex為組件里面索引為tex的
    }
    render() {
        return <div >
            <input type="text" ref="tex" />
            <input type="button" onClick={this.btnClick.bind(this)} value='click me' />
        </div>;//注意bind后面的this
    }
}
  • 事件target
    下面是一個事件對應要執行的函數的定義:
handleChange: function(event) {
    this.setState({value: event.target.value});//event.target.value元素的值
  }

每個控件取值不一樣,value是指input控件,下拉框為selected,radiobutton為checked。a標簽是innerHtml。可以自己通過console.info(e.target) 調試出自己想要的那個字段

ES6的坑

  • 類名(組件名)一定要用大寫開頭,否則自定義的組件無法編譯,識別不出來。
  • 類中定義render函數要注意兩點,見代碼注釋。
render() {//開頭花括號一定要和小括號隔一個空格,否則識別不出來
   return <ol>//標簽前一半一定要和return一行
     {
        React.Children.map(this.props.children, function (child) {
           return <li>{child}</li>;
        })
      }
   </ol>;
}
  • 在class中使用class的變量或者方法,一定要加個this。如this.handlerclick。
  • es6 綁定事件需要onClick={this.func1.bind(this)}
    這樣func1和bind里面的參數‘this’的作用域才綁定到了一起(注意es5是不需要這個bind(this)的),func1中如果有this.name這類語句,相當於是使用參數‘this’里面的變量值;或者使用箭頭函數func1= (e)=> {函數體}

小結

  經過這番簡單的練習后,如果還想看看做一個項目中如何使用react參見下章,一個模仿微博展示的demo(編寫ing)。
  本文沒有對react作深入的研究。通過學習react的使用方法可以看到,react入門的話相對於其他框架還是比較簡單的,代碼邏輯也很清晰,好維護也好使用。重要的是,需要使用者把從前直接對dom操作的思維方式轉換過來,相信會愛上它的。
  ps: react 還在發展期,學習的話建議英語好的直接看官方文檔,可以少走一些彎路。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM