React Native之React速學(xué)教程(上)
本文出自《React Native學(xué)習(xí)筆記》系列文章新翎。
React Native是基于React的锐膜,在開發(fā)React Native過程中少不了的需要用到React方面的知識乎折。雖然官方也有相應(yīng)的Document,但篇幅比較多,學(xué)起來比較枯燥。
通過《React Native之React速學(xué)教程》你可以對React有更系統(tǒng)和更深入的認(rèn)識攒巍。為了方便大家學(xué)習(xí),我將《React Native之React速學(xué)教程》分為上荒勇、中柒莉、下三篇,大家可以根據(jù)需要進(jìn)行閱讀學(xué)習(xí)沽翔。
概述
本篇為《React Native之React速學(xué)教程》的第一篇常柄。本篇將從React的特點、如何使用React搀擂、JSX語法西潘、組件(Component)以及組件的屬性,狀態(tài)等方面進(jìn)行講解哨颂。
What's React
React是一個用于組建用戶界面的JavaScript庫喷市,讓你以更簡單的方式來創(chuàng)建交互式用戶界面。
- 當(dāng)數(shù)據(jù)改變時威恼,React將高效的更新和渲染需要更新的組件品姓。聲明性視圖使你的代碼更可預(yù)測,更容易調(diào)試箫措。
- 構(gòu)建封裝管理自己的狀態(tài)的組件腹备,然后將它們組裝成復(fù)雜的用戶界面。由于組件邏輯是用JavaScript編寫的斤蔓,而不是模板植酥,所以你可以輕松地通過您的應(yīng)用程序傳遞豐富的數(shù)據(jù),并保持DOM狀態(tài)弦牡。
- 一次學(xué)習(xí)隨處可寫友驮,學(xué)習(xí)React,你不僅可以將它用于Web開發(fā)驾锰,也可以用于React Native來開發(fā)Android和iOS應(yīng)用卸留。
不是模板卻比模板更加靈活:

心得:上圖是GitHub Popular的首頁截圖,這個頁面是通過不同的組件組裝而成的椭豫,組件化的開發(fā)模式耻瑟,使得代碼在更大程度上的到復(fù)用,而且組件之間對的組裝很靈活赏酥。
Get Started
使用React之前需要在頁面引入如下js庫 喳整。
- react.js
- react-dom.js
- browser.min.js
上面一共列舉了三個庫: react.js 、react-dom.js 和 browser.min.js 今缚,它們必須首先加載算柳。其中,react.js 是 React 的核心庫姓言,react-dom.js 是提供與 DOM 相關(guān)的功能瞬项,browser.min.js 的作用是將 JSX 語法轉(zhuǎn)為 JavaScript 語法,這一步很消耗時間何荚,實際上線的時候囱淋,應(yīng)該將它放到服務(wù)器完成。
你可以從React官網(wǎng)下載這些庫餐塘,也可以將其下載到本地去使用妥衣。
心得:在做React Native開發(fā)時,這些庫作為React Native核心庫已經(jīng)被初始化在node_modules目錄下,所以不需要單獨下載税手。
使用React
解壓從上述地址下載的壓縮包蜂筹,在根目錄中創(chuàng)建一個包含以下內(nèi)容的 “helloworld.html” 。
<!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 轉(zhuǎn)成標(biāo)準(zhǔn)的 JavaScript,我們用<script type="text/babel">
標(biāo)簽兵扬,然后通過Babel轉(zhuǎn)換成在瀏覽器中真正執(zhí)行的內(nèi)容麻裳。
ReactDOM.render()
ReactDOM.render 是 React 的最基本方法,用于將模板轉(zhuǎn)為 HTML 語言器钟,并插入指定的 DOM 節(jié)點津坑。
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
上述代碼的作用是將<h1>Hello, world!</h1>
插入到元素id為example的容器中。
JSX
JSX 是一個看起來很像 XML 的 JavaScript 語法擴(kuò)展傲霸。
每一個XML標(biāo)簽都會被JSX轉(zhuǎn)換工具轉(zhuǎn)換成純JavaScript代碼疆瑰,使用JSX,組件的結(jié)構(gòu)和組件之間的關(guān)系看上去更加清晰狞谱。
JSX并不是React必須使用的乃摹,但React官方建議我們使用 JSX , 因為它能定義簡潔且我們熟知的包含屬性的樹狀結(jié)構(gòu)語法。
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標(biāo)簽 與 React組件 對比
React 可以渲染 HTML 標(biāo)簽 (strings) 或 React 組件 (classes)跟衅。
要渲染 HTML 標(biāo)簽孵睬,只需在 JSX 里使用小寫字母開頭的標(biāo)簽名。
var myDivElement = <div className="foo" />;
React.render(myDivElement, document.body);
要渲染 React 組件伶跷,只需創(chuàng)建一個大寫字母開頭的本地變量掰读。
var MyComponent = React.createClass({/*...*/});
var myElement = <MyComponent someProperty={true} />;
React.render(myElement, document.body);
提示:
- React 的 JSX 里約定分別使用首字母大、小寫來區(qū)分本地組件的類和 HTML 標(biāo)簽叭莫。
- 由于 JSX 就是 JavaScript蹈集,一些標(biāo)識符像 class 和 for 不建議作為 XML 屬性名。作為替代雇初, React DOM 使用 className 和 htmlFor 來做對應(yīng)的屬性拢肆。
JavaScript 表達(dá)式
屬性表達(dá)式
要使用 JavaScript 表達(dá)式作為屬性值,只需把這個表達(dá)式用一對大括號 ({}) 包起來靖诗,不要用引號 ("")郭怪。
// 輸入 (JSX):
var person = <Person name={window.isLoggedIn ? window.name : ''} />;
// 輸出 (JS):
var person = React.createElement(
Person,
{name: window.isLoggedIn ? window.name : ''}
);
子節(jié)點表達(dá)式
同樣地,JavaScript 表達(dá)式可用于描述子結(jié)點:
// 輸入 (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 表達(dá)式而已鄙才。你只需要在一個標(biāo)簽的子節(jié)點內(nèi)(非最外層)用 {} 包圍要注釋的部分。
class ReactDemo extends Component {
render() {
return (
<View style={styles.container}>
{/*標(biāo)簽子節(jié)點的注釋*/}
<Text style={styles.welcome}
//textAlign='right'
textShadowColor='yellow'
/*color='red'
textShadowRadius='1'*/
>
React Native!
</Text>
</View>
);
}
}
心得:在標(biāo)簽節(jié)點以外注釋促绵,和通常的注釋是一樣的攒庵,多行用“/**/” 單行用“//”嘴纺;
JSX延展屬性
不要試圖去修改組件的屬性
不推薦做法:
var component = <Component />;
component.props.foo = x; // 不推薦
component.props.bar = y; // 不推薦
這樣修改組件的屬性,會導(dǎo)致React不會對組件的屬性類型(propTypes)進(jìn)行的檢查浓冒。從而引發(fā)一些預(yù)料之外的問題栽渴。
推薦做法:
var component = <Component foo={x} bar={y} />;
延展屬性(Spread Attributes)
你可以使用 JSX 的新特性 - 延展屬性:
var props = {};
props.foo = x;
props.bar = y;
var component = <Component {...props} />;
傳入對象的屬性會被復(fù)制到組件內(nèi)。
它能被多次使用裆蒸,也可以和其它屬性一起用熔萧。注意順序很重要,后面的會覆蓋掉前面的僚祷。
var props = { foo: 'default' };
var component = <Component {...props} foo={'override'} />;
console.log(component.props.foo); // 'override'
上文出現(xiàn)的... 標(biāo)記被叫做延展操作符(spread operator)已經(jīng)被 ES6 數(shù)組 支持。
Component
React 允許將代碼封裝成組件(component)贮缕,然后像插入普通 HTML 標(biāo)簽一樣辙谜,在網(wǎng)頁中插入這個組件。
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 方法蜕琴,用于輸出組件。
注意
- 組件類的第一個字母必須大寫宵溅。
- 組件類只能包含一個頂層標(biāo)簽凌简。
組件的屬性(props)
我們可以通過this.props.xx
的形式獲取組件對象的屬性,對象的屬性可以任意定義恃逻,但要避免與JavaScript關(guān)鍵字沖突雏搂。
遍歷對象的屬性:
this.props.children
會返回組件對象的所有屬性。
React 提供一個工具方法 React.Children 來處理 this.props.children 寇损。我們可以用 React.Children.map
或React.Children.forEach
來遍歷子節(jié)點凸郑。
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
組件的屬性可以接受任意值矛市,字符串芙沥、對象、函數(shù)等等都可以浊吏。有時而昨,我們需要一種機(jī)制,驗證別人使用組件時卿捎,提供的參數(shù)是否符合要求配紫。
組件類的PropTypes屬性,就是用來驗證組件實例的屬性是否符合要求午阵。
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
},
render: function() {
return <h1> {this.props.title} </h1>;
}
});
上面的Mytitle組件有一個title屬性躺孝。PropTypes 告訴 React享扔,這個 title 屬性是必須的,而且它的值必須是字符串≈才郏現(xiàn)在惧眠,我們設(shè)置 title 屬性的值是一個數(shù)值。
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設(shè)置秀存,可以查看官方文檔。
此外羽氮,getDefaultProps 方法可以用來設(shè)置組件屬性的默認(rèn)值或链。
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節(jié)點)
組件并不是真實的 DOM 節(jié)點档押,而是存在于內(nèi)存之中的一種數(shù)據(jù)結(jié)構(gòu)澳盐,叫做虛擬 DOM (virtual DOM)。只有當(dāng)它插入文檔以后令宿,才會變成真實的 DOM 叼耙。根據(jù) React 的設(shè)計,所有的 DOM 變動粒没,都先在虛擬 DOM 上發(fā)生筛婉,然后再將實際發(fā)生變動的部分,反映在真實 DOM上革娄,這種算法叫做 DOM diff 倾贰,它可以極大提高網(wǎng)頁的性能表現(xiàn)。
但是拦惋,有時需要從組件獲取真實 DOM 的節(jié)點匆浙,這時就要用到 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 的子節(jié)點有一個文本輸入框首尼,用于獲取用戶的輸入。這時就必須獲取真實的 DOM 節(jié)點言秸,虛擬 DOM 是拿不到用戶輸入的软能。為了做到這一點,文本輸入框必須有一個 ref 屬性举畸,然后 this.refs.[refName] 就會返回這個真實的 DOM 節(jié)點查排。
需要注意的是,由于 this.refs.[refName] 屬性獲取的是真實 DOM 抄沮,所以必須等到虛擬 DOM 插入文檔以后跋核,才能使用這個屬性岖瑰,否則會報錯。上面代碼中砂代,通過為組件指定 Click 事件的回調(diào)函數(shù)蹋订,確保了只有等到真實 DOM 發(fā)生 Click 事件之后,才會讀取 this.refs.[refName] 屬性刻伊。
React 組件支持很多事件露戒,除了 Click 事件以外,還有 KeyDown 捶箱、Copy智什、Scroll 等,完整的事件清單請查看官方文檔讼呢。
心得:ref屬性在開發(fā)中使用頻率很高撩鹿,使用它你可以獲取到任何你想要獲取的組件的對象,有個這個對象你就可以靈活地做很多事情悦屏,比如:讀寫對象的變量,甚至調(diào)用對象的函數(shù)键思。
state
上文講到了props础爬,因為每個組件只會根據(jù)props 渲染了自己一次,props 是不可變的吼鳞。為了實現(xiàn)交互看蚜,可以使用組件的 state 。this.state 是組件私有的赔桌,可以通過getInitialState()
方法初始化供炎,通過調(diào)用 this.setState()
來改變它。當(dāng) state 更新之后疾党,組件就會重新渲染自己音诫。
render() 方法依賴于 this.props 和 this.state ,框架會確保渲染出來的 UI 界面總是與輸入( this.props 和 this.state )保持一致雪位。
初始化state
通過getInitialState()
方法初始化state竭钝,在組件的生命周期中僅執(zhí)行一次,用于設(shè)置組件的初始化 state 雹洗。
getInitialState:function(){
return {favorite:false};
}
更新 state
通過this.setState()
方法來更新state香罐,調(diào)用該方法后脆荷,React會重新渲染相關(guān)的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 方法用于定義初始狀態(tài)搀菩,也就是一個對象螃成,這個對象可以通過 this.state 屬性讀取旦签。當(dāng)用戶點擊組件查坪,導(dǎo)致狀態(tài)變化,this.setState 方法就修改狀態(tài)值顷霹,每次修改以后咪惠,自動調(diào)用 this.render 方法,再次渲染組件淋淀。
心得:由于 this.props 和 this.state 都用于描述組件的特性遥昧,可能會產(chǎn)生混淆。一個簡單的區(qū)分方法是朵纷,this.props 表示那些一旦定義炭臭,就不再改變的特性,而 this.state 是會隨著用戶互動而產(chǎn)生變化的特性袍辞。
參考
React's official site
React on ES6+
About
本文出自《React Native學(xué)習(xí)筆記》系列文章鞋仍。
了解更多,可以關(guān)注我的GitHub
@http://jiapenghui.com
推薦閱讀
- React Native 學(xué)習(xí)筆記
- [Reac Native布局詳細(xì)指南](https://github.com/crazycodeboy/RNStudyNotes/tree/master/React Native布局/React Native布局詳細(xì)指南/React Native布局詳細(xì)指南.md)
- React Native調(diào)試技巧與心得
- React Native發(fā)布APP之簽名打包APK
- React Native應(yīng)用部署搅吁、熱更新-CodePush最新集成總結(jié)