本篇爲《React Native之React速學教程》的第一篇。本篇將從React的特色、如何使用React、JSX語法、組件(Component)以及組件的屬性,狀態等方面進行講解。javascript
React是一個用於組建用戶界面的JavaScript庫,讓你以更簡單的方式來建立交互式用戶界面。html
不是模板卻比模板更加靈活:java
心得:上圖是GitHub Popular的首頁截圖,這個頁面是經過不一樣的組件組裝而成的,組件化的開發模式,使得代碼在更大程度上的到複用,並且組件之間對的組裝很靈活。node
使用React以前須要在頁面引入以下js庫 。react
上面一共列舉了三個庫: 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
解壓從上述地址下載的壓縮包,在根目錄中建立一個包含如下內容的 「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 是 React 的最基本方法,用於將模板轉爲 HTML 語言,並插入指定的 DOM 節點。npm
ReactDOM.render(
<h1>Hello, world!</h1>, document.getElementById('example') );
上述代碼的做用是將<h1>Hello, world!</h1>
插入到元素id爲example的容器中。
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') );
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 表達式做爲屬性值,只需把這個表達式用一對大括號 ({}) 包起來,不要用引號 (「」)。
// 輸入 (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> ); } }
心得:在標籤節點之外註釋,和一般的註釋是同樣的,多行用「/**/」 單行用「//」;
不推薦作法:
var component = <Component />; component.props.foo = x; // 不推薦 component.props.bar = y; // 不推薦
這樣修改組件的屬性,會致使React不會對組件的屬性類型(propTypes)進行的檢查。從而引起一些預料以外的問題。
推薦作法:
var component = <Component foo={x} bar={y} />;
你可使用 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 數組 支持。
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 方法,用於輸出組件。
注意
咱們能夠經過this.props.xx
的形式獲取組件對象的屬性,對象的屬性能夠任意定義,但要避免與JavaScript關鍵字衝突。
this.props.children
會返回組件對象的全部屬性。
React 提供一個工具方法 React.Children 來處理 this.props.children 。咱們能夠用 React.Children.map
或React.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屬性,就是用來驗證組件實例的屬性是否符合要求。
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"
。
組件並非真實的 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屬性在開發中使用頻率很高,使用它你能夠獲取到任何你想要獲取的組件的對象,有個這個對象你就能夠靈活地作不少事情,好比:讀寫對象的變量,甚至調用對象的函數。
上文講到了props,由於每一個組件只會根據props 渲染了本身一次,props 是不可變的。爲了實現交互,可使用組件的 state 。this.state 是組件私有的,能夠經過getInitialState()
方法初始化,經過調用 this.setState()
來改變它。當 state 更新以後,組件就會從新渲染本身。
render() 方法依賴於 this.props 和 this.state ,框架會確保渲染出來的 UI 界面老是與輸入( this.props 和 this.state )保持一致。
經過getInitialState()
方法初始化state,在組件的生命週期中僅執行一次,用於設置組件的初始化 state 。
getInitialState:function(){
return {favorite:false};
}
經過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 是會隨着用戶互動而產生變化的特性。