React Native之React速學教程(中)

概述

本篇爲《React Native之React速學教程》的第一篇。本篇將從React的特色、如何使用React、JSX語法、組件(Component)以及組件的屬性,狀態等方面進行講解。javascript

What’s React

React是一個用於組建用戶界面的JavaScript庫,讓你以更簡單的方式來建立交互式用戶界面。html

  1. 當數據改變時,React將高效的更新和渲染須要更新的組件。聲明性視圖使你的代碼更可預測,更容易調試。
  2. 構建封裝管理本身的狀態的組件,而後將它們組裝成複雜的用戶界面。因爲組件邏輯是用JavaScript編寫的,而不是模板,因此你能夠輕鬆地經過您的應用程序傳遞豐富的數據,並保持DOM狀態。
  3. 一次學習隨處可寫,學習React,你不只能夠將它用於Web開發,也能夠用於React Native來開發Android和iOS應用。

不是模板卻比模板更加靈活:java

Component

心得:上圖是GitHub Popular的首頁截圖,這個頁面是經過不一樣的組件組裝而成的,組件化的開發模式,使得代碼在更大程度上的到複用,並且組件之間對的組裝很靈活。node

Get Started

使用React以前須要在頁面引入以下js庫 。react

  • react.js
  • react-dom.js
  • browser.min.js

上面一共列舉了三個庫: react.js 、react-dom.js 和 browser.min.js ,它們必須首先加載。其中,react.js 是 React 的核心庫,react-dom.js 是提供與 DOM 相關的功能,browser.min.js 的做用是將 JSX 語法轉爲 JavaScript 語法,這一步很消耗時間,實際上線的時候,應該將它放到服務器完成。
你能夠從React官網下載這些庫,也能夠將其下載到本地去使用。git

心得:在作React Native開發時,這些庫做爲React Native核心庫已經被初始化在node_modules目錄下,因此不須要單獨下載。es6

使用React

解壓從上述地址下載的壓縮包,在根目錄中建立一個包含如下內容的 「helloworld.html」 。github

<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello React!</title> <script src="build/react.js"></script> <script src="build/react-dom.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/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> 

在 JavaScript 代碼裏寫着 XML 格式的代碼稱爲 JSX,下文會介紹。爲了把 JSX 轉成標準的 JavaScript,咱們用<script type="text/babel">標籤,而後經過Babel轉換成在瀏覽器中真正執行的內容。算法

ReactDOM.render()

ReactDOM.render 是 React 的最基本方法,用於將模板轉爲 HTML 語言,並插入指定的 DOM 節點。npm

ReactDOM.render(
  <h1>Hello, world!</h1>, document.getElementById('example') ); 

上述代碼的做用是將<h1>Hello, world!</h1>插入到元素id爲example的容器中。

JSX

JSX 是一個看起來很像 XML 的 JavaScript 語法擴展。 每個XML標籤都會被JSX轉換工具轉換成純JavaScript代碼,使用JSX,組件的結構和組件之間的關係看上去更加清晰。
JSX並非React必須使用的,但React官方建議咱們使用 JSX , 由於它能定義簡潔且咱們熟知的包含屬性的樹狀結構語法。

Usage:

React.render(//使用JSX
    <div> <div> <div>content</div> </div> </div>, document.getElementById('example') ); React.render(//不使用JSX React.createElement('div', null, React.createElement('div', null, React.createElement('div', null, 'content') ) ), document.getElementById('example') ); 

HTML標籤 與 React組件 對比

React 能夠渲染 HTML 標籤 (strings) 或 React 組件 (classes)。 
要渲染 HTML 標籤,只需在 JSX 裏使用小寫字母開頭的標籤名。

var myDivElement = <div className="foo" />; React.render(myDivElement, document.body); 

要渲染 React 組件,只需建立一個大寫字母開頭的本地變量。

var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />; React.render(myElement, document.body); 

提示:

  • React 的 JSX 里約定分別使用首字母大、小寫來區分本地組件的類和 HTML 標籤。
  • 因爲 JSX 就是 JavaScript,一些標識符像 class 和 for 不建議做爲 XML 屬性名。做爲替代, React DOM 使用 className 和 htmlFor 來作對應的屬性。

JavaScript 表達式

屬性表達式

要使用 JavaScript 表達式做爲屬性值,只需把這個表達式用一對大括號 ({}) 包起來,不要用引號 (「」)。

// 輸入 (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />; // 輸出 (JS): var person = React.createElement( Person, {name: window.isLoggedIn ? window.name : ''} ); 

子節點表達式

一樣地,JavaScript 表達式可用於描述子結點:

// 輸入 (JSX):
var content = <Container>{window.isLoggedIn ? <Nav /> : <Login />}</Container>; // 輸出 (JS): var content = React.createElement( Container, null, window.isLoggedIn ? React.createElement(Nav) : React.createElement(Login) ); 

註釋

JSX 裏添加註釋很容易;它們只是 JS 表達式而已。你只須要在一個標籤的子節點內(非最外層)用 {} 包圍要註釋的部分。

class ReactDemo extends Component {
  render() {
    return (     
      <View style={styles.container}> {/*標籤子節點的註釋*/} <Text style={styles.welcome} //textAlign='right' textShadowColor='yellow' /*color='red' textShadowRadius='1'*/ > React Native! </Text> </View> ); } } 

心得:在標籤節點之外註釋,和一般的註釋是同樣的,多行用「/**/」 單行用「//」;

JSX延展屬性

不要試圖去修改組件的屬性

不推薦作法:

var component = <Component />; component.props.foo = x; // 不推薦 component.props.bar = y; // 不推薦 

這樣修改組件的屬性,會致使React不會對組件的屬性類型(propTypes)進行的檢查。從而引起一些預料以外的問題。

推薦作法:

var component = <Component foo={x} bar={y} />; 

延展屬性(Spread Attributes)

你可使用 JSX 的新特性 - 延展屬性:

var props = {};
  props.foo = x;
  props.bar = y;
  var component = <Component {...props} />; 

傳入對象的屬性會被複制到組件內。

它能被屢次使用,也能夠和其它屬性一塊兒用。注意順序很重要,後面的會覆蓋掉前面的。

var props = { foo: 'default' };
  var component = <Component {...props} foo={'override'} />; console.log(component.props.foo); // 'override' 

上文出現的… 標記被叫作延展操做符(spread operator)已經被 ES6 數組 支持。

Component

React 容許將代碼封裝成組件(component),而後像插入普通 HTML 標籤同樣,在網頁中插入這個組件。

var HelloMessage = React.createClass({
  render: function() {
    return <h1>Hello {this.props.name}</h1>; } }); ReactDOM.render( <HelloMessage name="John" />, document.getElementById('example') ); 

上面代碼中,變量 HelloMessage 就是一個組件類。模板插入 <HelloMessage /> 時,會自動生成 HelloMessage 的一個實例。全部組件類都必須有本身的 render 方法,用於輸出組件。

注意

  • 組件類的第一個字母必須大寫。
  • 組件類只能包含一個頂層標籤。

組件的屬性(props)

咱們能夠經過this.props.xx的形式獲取組件對象的屬性,對象的屬性能夠任意定義,但要避免與JavaScript關鍵字衝突。

遍歷對象的屬性:

this.props.children會返回組件對象的全部屬性。
React 提供一個工具方法 React.Children 來處理 this.props.children 。咱們能夠用 React.Children.mapReact.Children.forEach 來遍歷子節點。 
React.Children.map

array React.Children.map(object children, function fn [, object thisArg])

該方法會返回一個array。
React.Children.forEach

React.Children.forEach(object children, function fn [, object thisArg])

Usage:

var NotesList = React.createClass({
  render: function() {
    return (
      <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body ); 

PropTypes

組件的屬性能夠接受任意值,字符串、對象、函數等等均可以。有時,咱們須要一種機制,驗證別人使用組件時,提供的參數是否符合要求。
組件類的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 屬性的值是一個數值。

var data = 123;
ReactDOM.render(
  <MyTitle title={data} />, document.body ); 

這樣一來,title屬性就通不過驗證了。控制檯會顯示一行錯誤信息。

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

更多的PropTypes設置,能夠查看官方文檔
此外,getDefaultProps 方法能夠用來設置組件屬性的默認值。

var MyTitle = React.createClass({
  getDefaultProps : function () {
    return {
      title : 'Hello World'
    };
  },
  render: function() {
     return <h1> {this.props.title} </h1>; } }); ReactDOM.render( <MyTitle />, document.body ); 

上面代碼會輸出"Hello World"

ref 屬性(獲取真實的DOM節點)

組件並非真實的 DOM 節點,而是存在於內存之中的一種數據結構,叫作虛擬 DOM (virtual DOM)。只有當它插入文檔之後,纔會變成真實的 DOM 。根據 React 的設計,全部的 DOM 變更,都先在虛擬 DOM 上發生,而後再將實際發生變更的部分,反映在真實 DOM上,這種算法叫作 DOM diff ,它能夠極大提升網頁的性能表現。

可是,有時須要從組件獲取真實 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> ); } }); ReactDOM.render( <MyComponent />, document.getElementById('example') ); 

上面代碼中,組件 MyComponent 的子節點有一個文本輸入框,用於獲取用戶的輸入。這時就必須獲取真實的 DOM 節點,虛擬 DOM 是拿不到用戶輸入的。爲了作到這一點,文本輸入框必須有一個 ref 屬性,而後 this.refs.[refName] 就會返回這個真實的 DOM 節點。
須要注意的是,因爲 this.refs.[refName] 屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯。上面代碼中,經過爲組件指定 Click 事件的回調函數,確保了只有等到真實 DOM 發生 Click 事件以後,纔會讀取 this.refs.[refName] 屬性。
React 組件支持不少事件,除了 Click 事件之外,還有 KeyDown 、Copy、Scroll 等,完整的事件清單請查看官方文檔

心得:ref屬性在開發中使用頻率很高,使用它你能夠獲取到任何你想要獲取的組件的對象,有個這個對象你就能夠靈活地作不少事情,好比:讀寫對象的變量,甚至調用對象的函數。

state

上文講到了props,由於每一個組件只會根據props 渲染了本身一次,props 是不可變的。爲了實現交互,可使用組件的 state 。this.state 是組件私有的,能夠經過getInitialState()方法初始化,經過調用 this.setState() 來改變它。當 state 更新以後,組件就會從新渲染本身。 
render() 方法依賴於 this.props 和 this.state ,框架會確保渲染出來的 UI 界面老是與輸入( this.props 和 this.state )保持一致。

初始化state

經過getInitialState() 方法初始化state,在組件的生命週期中僅執行一次,用於設置組件的初始化 state 。

getInitialState:function(){
    return {favorite:false};
  }

更新 state

經過this.setState()方法來更新state,調用該方法後,React會從新渲染相關的UI。
this.setState({favorite:!this.state.favorite});

Usage:

var FavoriteButton=React.createClass({
  getInitialState:function(){
    return {favorite:false};
  },
  handleClick:function(event){
    this.setState({favorite:!this.state.favorite});
  },
  render:function(){
    var text=this.state.favorite? 'favorite':'un favorite';
    return (
      <div type='button' onClick={this.handleClick}> You {text} this. Click to toggle. </div> ); } }); 

上面代碼是一個 FavoriteButton 組件,它的 getInitialState 方法用於定義初始狀態,也就是一個對象,這個對象能夠經過 this.state 屬性讀取。當用戶點擊組件,致使狀態變化,this.setState 方法就修改狀態值,每次修改之後,自動調用 this.render 方法,再次渲染組件。

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

參考

React’s official site
React on ES6+

相關文章
相關標籤/搜索