搭建開發(fā)環(huán)境
- 目標(biāo)平臺:IOS
- 開發(fā)平臺:macOS
安裝
必需的軟件
Homebrew
Homebrew, Mac系統(tǒng)的包管理器耗帕,用于安裝NodeJS和一些其他必需的工具軟件春弥。
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
譯注:在Max OS X 10.11(El Capitan)版本中,homebrew在安裝軟件時可能會碰到/usr/local
目錄不可寫的權(quán)限問題⊥可以使用下面的命令修復(fù):
sudo chown -R `whoami` /usr/local
Node
使用Homebrew來安裝node.js.
React Native目前需要NodeJS 5.0或更高版本碳竟。本文發(fā)布時Homebrew默認(rèn)安裝的是最新版本种远,一般都滿足要求款筑。
brew install node
安裝完node后建議設(shè)置npm鏡像以加速后面的過程(或使用科學(xué)上網(wǎng)工具)腋么。注意:不要使用cnpm咕娄!cnpm安裝的模塊路徑比較奇怪,packager不能正常識別珊擂!
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
Yarn圣勒、React Native的命令行工具(react-native-cli)
Yarn是Facebook提供的替代npm的工具,可以加速node模塊的下載摧扇。React Native的命令行工具用于執(zhí)行創(chuàng)建圣贸、初始化、更新項目扛稽、運(yùn)行打包服務(wù)(packager)等任務(wù)吁峻。
npm install -g yarn react-native-cli
安裝完yarn后同理也要設(shè)置鏡像源:
yarn config set registry https://registry.npm.taobao.org --global
yarn config set disturl https://npm.taobao.org/dist --global
如果你看到EACCES: permission denied
這樣的權(quán)限報錯,那么請參照上文的homebrew譯注在张,修復(fù)/usr/local
目錄的所有權(quán):
sudo chown -R `whoami` /usr/local
Xcode
React Native目前需要Xcode 8.0 或更高版本用含。你可以通過App Store或是到Apple開發(fā)者官網(wǎng)上下載。這一步驟會同時安裝Xcode IDE和Xcode的命令行工具帮匾。
雖然一般來說命令行工具都是默認(rèn)安裝了啄骇,但你最好還是啟動Xcode,并在
Xcode | Preferences | Locations
菜單中檢查一下是否裝有某個版本的Command Line Tools
瘟斜。Xcode的命令行工具中也包含一些必須的工具缸夹,比如git
等。
推薦安裝的工具
Watchman
Watchman是由Facebook提供的監(jiān)視文件系統(tǒng)變更的工具螺句。安裝此工具可以提高開發(fā)時的性能(packager可以快速捕捉文件的變化從而實現(xiàn)實時刷新)虽惭。
brew install watchman
Flow
Flow是一個靜態(tài)的JS類型檢查工具。譯注:你在很多示例中看到的奇奇怪怪的冒號問號蛇尚,以及方法參數(shù)中像類型一樣的寫法趟妥,都是屬于這個flow工具的語法。這一語法并不屬于ES標(biāo)準(zhǔn)佣蓉,只是Facebook自家的代碼規(guī)范披摄。所以新手可以直接跳過(即不需要安裝這一工具,也不建議去費(fèi)力學(xué)習(xí)flow相關(guān)語法)勇凭。
brew install flow
vscode
推薦使用vscode疚膊。安裝以下插件:
Document this
EditorConfig for VS Code
EsLint
Flow Language Support
JavaScript (ES6) code snippets
jsx
React Native Tools
Reactjs code snippet
vscode-todo
測試安裝
react-native init AwesomeProject
cd AwesomeProject
react-native run-ios
修改項目
- 使用你喜歡的編輯器打開
index.ios.js
并隨便改上幾行。 - 在iOS Emulator中按下
?-R
就可以刷新APP并看到你的最新修改虾标!
為已有的React Native工程添加Android支持
如果已經(jīng)有了一個只有IOS版本的React Native工程寓盗,并且希望添加Android支持,需要在工程目錄下運(yùn)行以下命令:
- 打開
package.json
文件,在dependencies項中找到react-native
傀蚌,并將其后的版本號修改為最新版本基显。 $ npm install
$ react-native android
動畫
在React Native中,我們已經(jīng)可以聯(lián)合使用兩個互補(bǔ)的系統(tǒng):用于全局的布局動畫LayoutAnimation,和用于創(chuàng)建更精細(xì)的交互控制的動畫Animated.
Animated
Animated
僅關(guān)注動畫的輸入與輸出聲明善炫,在其中建立一個可配置的變化函數(shù)撩幽,然后使用簡單的start/stop
方法來控制動畫按順序執(zhí)行。
class Playground extends React.Component {
constructor(props: any) {
super(props);
this.state = {
bounceValue: new Animated.Value(0),
};
}
render(): ReactElement {
return (
<Animated.Image // 可選的基本組件類型: Image, Text, View
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
style={{
flex: 1,
transform: [ // `transform`是一個有序數(shù)組(動畫按順序執(zhí)行)
{scale: this.state.bounceValue}, // 將`bounceValue`賦值給 `scale`
]
}}
/>
);
}
componentDidMount() {
this.state.bounceValue.setValue(1.5); // 設(shè)置一個較大的初始值
Animated.spring( // 可選的基本動畫類型: spring, decay, timing
this.state.bounceValue, // 將`bounceValue`值動畫化
{
toValue: 0.8, // 將其值以動畫的形式改到一個較小值
friction: 1, // Bouncier spring
}
).start(); // 開始執(zhí)行動畫
}
}
bounceValue
在構(gòu)造函數(shù)中初始化為state
的一部分箩艺,然后和圖片的縮放比例進(jìn)行綁定窜醉。在動畫執(zhí)行的背后,其數(shù)值會被不斷的計算并用于設(shè)置縮放比例艺谆。當(dāng)組件剛剛掛載的時候榨惰,縮放比例被設(shè)置到1.5。然后緊跟著在bounceValue
上執(zhí)行了一個彈跳動畫(spring)静汤,會逐幀刷新數(shù)值琅催,并同步更新所有依賴本數(shù)值的綁定(在這個例子里,就是圖片的縮放比例)虫给。比起調(diào)用setState
然后重新渲染藤抡,這一運(yùn)行過程要快得多。因為整個配置都是聲明式的狰右,我們可以實現(xiàn)更進(jìn)一步的優(yōu)化,只要序列化好配置舆床,然后我們可以在一個高優(yōu)先級的線程執(zhí)行動畫棋蚌。
核心API
我們所需要的東西都來自于Animated模塊。包括兩個值類型挨队,Value用于單個值谷暮,而ValueXY用于向量值;還包括三種動畫類型盛垦,spring, decay, 還有timing, 以及三種組件類型湿弦,View Text, Image。我們可以使用Animated.createAnimatedComponent
方法來對其它類型的組件創(chuàng)建動畫腾夯。
這三種動畫類型可以用來創(chuàng)建幾乎任何你需要的動畫曲線颊埃,因為它們每一個都可以被自定義:
-
spring
: 基礎(chǔ)的單次彈跳物理模型friction
: 摩擦力,默認(rèn)為7.tension
: 張力蝶俱,默認(rèn)40班利。 -
decay
: 以一個初始速度開始并且逐漸減慢停止。velocity
: 起始速度榨呆,必填參數(shù)罗标。deceleration
: 速度衰減比例,默認(rèn)為0.997。 -
timing
: 從時間范圍映射到漸變的值闯割。duration
: 動畫持續(xù)的時間(單位是毫秒)彻消,默認(rèn)為500。easing
:一個用于定義曲線的漸變函數(shù)宙拉。閱讀Easing
模塊可以找到許多預(yù)定義的函數(shù)宾尚。iOS默認(rèn)為Easing.inOut(Easing.ease)
。delay
: 在一段時間之后開始動畫(單位是毫秒)鼓黔,默認(rèn)為0央勒。
動畫可以通過調(diào)用start
方法來開始。start
接受一個回調(diào)函數(shù)澳化,當(dāng)動畫結(jié)束的時候會調(diào)用此回調(diào)函數(shù)崔步。如果動畫是因為正常播放完成而結(jié)束的,回調(diào)函數(shù)被調(diào)用時的參數(shù)為{finished: true}
缎谷,但若動畫是在結(jié)束之前被調(diào)用了stop
而結(jié)束(可能是被一個手勢或者其它的動畫打斷)井濒,它會收到參數(shù){finished: false}
。
動畫組合
多個動畫可以通過parallel
(同時執(zhí)行)列林、sequence
(順序執(zhí)行)瑞你、stagger
和delay
來組合使用。它們中的每一個都接受一個要執(zhí)行的動畫數(shù)組希痴,并且自動在適當(dāng)?shù)臅r候調(diào)用start/stop者甲。舉個例子:
Animated.sequence([ // 首先執(zhí)行decay動畫,結(jié)束后同時執(zhí)行spring和twirl動畫
Animated.decay(position, { // 滑行一段距離后停止
velocity: {x: gestureState.vx, y: gestureState.vy}, // 根據(jù)用戶的手勢設(shè)置速度
deceleration: 0.997,
}),
Animated.parallel([ // 在decay之后并行執(zhí)行:
Animated.spring(position, {
toValue: {x: 0, y: 0} // 返回到起始點(diǎn)開始
}),
Animated.timing(twirl, { // 同時開始旋轉(zhuǎn)
toValue: 360,
}),
]),
]).start(); // 執(zhí)行這一整套動畫序列
默認(rèn)情況下砌创,如果任何一個動畫被停止或中斷了虏缸,組內(nèi)所有其它的動畫也會被停止。Parallel有一個stopTogether
屬性嫩实,如果設(shè)置為false
刽辙,可以禁用自動停止。
跟蹤動態(tài)值
動畫中所設(shè)的值還可以通過跟蹤別的值得到甲献。你只要把toValue設(shè)置成另一個動態(tài)值而不是一個普通數(shù)字就行了宰缤。比如我們可以用彈跳動畫來實現(xiàn)聊天頭像的閃動,又比如通過timing
設(shè)置duration:0
來實現(xiàn)快速的跟隨晃洒。他們還可以使用插值來進(jìn)行組合:
Animated.spring(follower, {toValue: leader}).start();
Animated.timing(opacity, {
toValue: pan.x.interpolate({
inputRange: [0, 300],
outputRange: [1, 0],
}),
}).start();
ValueXY
是一個方便的處理2D交互的辦法慨灭,譬如旋轉(zhuǎn)或拖拽。它是一個簡單的包含了兩個Animated.Value
實例的包裝球及,然后提供了一系列輔助函數(shù)缘挑,使得ValueXY
在許多時候可以替代Value
來使用。比如在上面的代碼片段中桶略,leader
和follower
可以同時為valueXY
類型语淘,這樣x和y的值都會被跟蹤诲宇。
輸入事件
Animated.event
是Animated API中與輸入有關(guān)的部分,允許手勢或其它事件直接綁定到動態(tài)值上惶翻。它通過一個結(jié)構(gòu)化的映射語法來完成姑蓝,使得復(fù)雜事件對象中的值可以被正確的解開。第一層是一個數(shù)組吕粗,允許同時映射多個值纺荧,然后數(shù)組的每一個元素是一個嵌套的對象。在下面的例子里颅筋,你可以發(fā)現(xiàn)scrollX
被映射到了event.nativeEvent.contentOffset.x
(event
通常是回調(diào)函數(shù)的第一個參數(shù))宙暇,并且pan.x
和pan.y
分別映射到gestureState.dx
和gestureState.dy
(gestureState
是傳遞給PanResponder
回調(diào)函數(shù)的第二個參數(shù))。
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {x: scrollX}}}] // scrollX = e.nativeEvent.contentOffset.x
)}
onPanResponderMove={Animated.event([
null, // 忽略原生事件
{dx: pan.x, dy: pan.y} // 從gestureState中解析出dx和dy的值
]);
響應(yīng)當(dāng)前的動畫值
你可能會注意到這里沒有一個明顯的方法來在動畫的過程中讀取當(dāng)前的值——這是出于優(yōu)化的角度考慮议泵,有些值只有在原生代碼運(yùn)行階段中才知道占贫。如果你需要在JavaScript中響應(yīng)當(dāng)前的值,有兩種可能的辦法:
-
spring.stopAnimation(callback)
會停止動畫并且把最終的值作為參數(shù)傳遞給回調(diào)函數(shù)callback
——這在處理手勢動畫的時候非常有用先口。 -
spring.addListener(callback)
會在動畫的執(zhí)行過程中持續(xù)異步調(diào)用callback
回調(diào)函數(shù)型奥,提供一個最近的值作為參數(shù)。這在用于觸發(fā)狀態(tài)切換的時候非常有用碉京,譬如當(dāng)用戶拖拽一個東西靠近的時候彈出一個新的氣泡選項厢汹。不過這個狀態(tài)切換可能并不會十分靈敏,因為它不像許多連續(xù)手勢操作(如旋轉(zhuǎn))那樣在60fps下運(yùn)行谐宙。
LayoutAnimation
LayoutAnimation
允許你在全局范圍內(nèi)創(chuàng)建
和更新
動畫烫葬,這些動畫會在下一次渲染或布局周期運(yùn)行。它常用來更新flexbox布局凡蜻,因為它可以無需測量或者計算特定屬性就能直接產(chǎn)生動畫搭综。尤其是當(dāng)布局變化可能影響到父節(jié)點(diǎn)(譬如“查看更多”展開動畫既增加父節(jié)點(diǎn)的尺寸又會將位于本行之下的所有行向下推動)時,如果不使用LayoutAnimation
咽瓷,可能就需要顯式聲明組件的坐標(biāo)设凹,才能使得所有受影響的組件能夠同步運(yùn)行動畫舰讹。
注意盡管LayoutAnimation
非常強(qiáng)大且有用茅姜,但它對動畫本身的控制沒有Animated
或者其它動畫庫那樣方便,所以如果你使用LayoutAnimation
無法實現(xiàn)一個效果月匣,那可能還是要考慮其他的方案钻洒。
requestAnimationFrame
requestAnimationFrame
是一個對瀏覽器標(biāo)準(zhǔn)API的兼容實現(xiàn),你可能已經(jīng)熟悉它了锄开。它接受一個函數(shù)作為唯一的參數(shù)素标,并且在下一次重繪之前調(diào)用此函數(shù)。一些基于JavaScript的動畫庫高度依賴于這一API萍悴。通常你不必直接調(diào)用它——那些動畫庫會替你管理好幀的更新头遭。
關(guān)于setNativeProps
setNativeProps
方法可以使我們直接修改基于原生視圖的組件的屬性寓免,而不需要使用setState
來重新渲染整個組件樹。如果我們發(fā)現(xiàn)動畫丟幀计维,可以嘗試使用setNativeProps或者shouldComponentUpdate來優(yōu)化它們袜香。有時候可能還需要將部分計算工作放在動畫完成之后進(jìn)行,這時候可以使用interactionManager
定時器
定時器是一個應(yīng)用中非常重要的部分鲫惶。React Native實現(xiàn)了和瀏覽器一致的定時器Timer蜈首。
定時器
- setTimeout, clearTimeout
- setInterval, clearInterval
- setImmediate, clearImmediate
- requestAnimationFrame, cancelAnimationFrame
requestAnimationFrame(fn)
和setTimeout(fn, 0)
不同,前者會在每幀刷新之后執(zhí)行一次欠母,而后者則會盡可能快的執(zhí)行(在iPhone5S上有可能每秒1000次以上)欢策。
setImmediate
則會在當(dāng)前JavaScript執(zhí)行塊結(jié)束的時候執(zhí)行,就在將要發(fā)送批量響應(yīng)數(shù)據(jù)到原生之前赏淌。注意如果你在setImmediate
的回調(diào)函數(shù)中又執(zhí)行了setImmediate
踩寇,它會緊接著立刻執(zhí)行,而不會在調(diào)用之前等待原生代碼猜敢。
Promise
的實現(xiàn)就使用了setImmediate
來執(zhí)行異步調(diào)用姑荷。
InteractionManager
原生應(yīng)用感覺如此流暢的一個重要原因就是在互動和動畫過程中避免繁重的操作。在React Native中缩擂,我們目前受到限制鼠冕,因為我們只有一個JavaScript執(zhí)行線程。不過我們可以使用InteractionManager
來確保在執(zhí)行繁重工作之前所有的交互和動畫都已處理完畢胯盯。應(yīng)用可以通過以下代碼來安排一個任務(wù)懈费,使其在交互之后執(zhí)行:
InteractionManager.runAfterInteractions(() => { // ...需要長時間同步執(zhí)行 })
我們來把它和之前的幾個任務(wù)安排方法對比一下:
- requestAnimationFrame(): 用來執(zhí)行在一段時間內(nèi)控制視圖動畫的代碼
- setImmediate/setTimeout/setInterval(): 在稍后執(zhí)行代碼。注意這有可能會延遲當(dāng)前正在進(jìn)行的動畫博脑。
- runAfterInteractions(): 在稍后執(zhí)行代碼憎乙,不會延遲當(dāng)前進(jìn)行的動畫。
觸摸處理系統(tǒng)會把一個或多個進(jìn)行中的觸摸操作認(rèn)定為'交互'叉趣,并且會將runAfterInteractions()
的回調(diào)函數(shù)延遲執(zhí)行泞边,直到所有的觸摸操作都結(jié)束或取消了。
InteractionManager還允許應(yīng)用注冊動畫疗杉,在動畫開始時創(chuàng)建一個交互“句柄”阵谚,然后在結(jié)束的時候清除它。
var handle = InteractionManager.createInteractionHandle();
// 執(zhí)行動畫... (`runAfterInteractions`中的任務(wù)現(xiàn)在開始排隊等候)
// 在動畫完成之后
InteractionManager.clearInteractionHandle(handle);
// 在所有句柄都清除之后烟具,現(xiàn)在開始依序執(zhí)行隊列中的任務(wù)
TimerMixin
我們發(fā)現(xiàn)很多React Native應(yīng)用發(fā)生致命錯誤(閃退)是與計時器有關(guān)梢什。具體來說,是在某個組件被卸載(unmount)之后朝聋,計時器卻仍然被激活嗡午。為了解決這個問題,我們引入了TimerMixin
冀痕。如果你在組件中引入TimerMixin
荔睹,就可以把你原本的setTimeout(fn, 500)
改為this.setTimeout(fn, 500)
(只需要在前面加上this.
)狸演,然后當(dāng)你的組件卸載時,所有的計時器事件也會被正確的清除僻他。
這個庫并沒有跟著React Native一起發(fā)布严沥。你需要在項目文件夾下輸入npm i react-timer-mixin --save
來單獨(dú)安裝它。
var TimerMixin = require('react-timer-mixin');
var Component = React.createClass({
mixins: [TimerMixin],
componentDidMount: function() {
this.setTimeout(
() => { console.log('這樣我就不會導(dǎo)致內(nèi)存泄露!'); },
500
);
}
});
注意:Mixin屬于ES5語法中姜,對于ES6來說消玄,無法直接使用Mixin。如果項目使用的是ES6代碼編寫丢胚,同時又使用定時器翩瓜,那么你只需要銘記在unmount組件時清除(clearTimeout/clearInterval)所有用到的定時器,那么也可以實現(xiàn)和TimerMixin同樣的效果携龟。
import React,{
Component
} from 'react';
export default class Hello extends Component {
componentDidMount() {
this.timer = setTimeout(
() => { console.log('把一個定時器的引用掛在this上'); },
500
);
}
componentWillUnmount() {
// 如果存在this.timer兔跌,則使用clearTimeout清空。
// 如果你使用多個timer峡蟋,那么用多個變量坟桅,或者用個數(shù)組來保存引用,然后逐個clear
this.timer && clearTimeout(this.timer); //true&&表達(dá)式 執(zhí)行表達(dá)式
}
};
直接操作
有時候我們需要直接改動組件并觸發(fā)局部的刷新蕊蝗,但不使用state或是props仅乓。在React Native中,setNativeProps就是等價于直接操作DOM節(jié)點(diǎn)的方法蓬戚。
在(不得不)頻繁刷新而又遇到瓶頸時夸楣,我們會使用setNativeProps;
直接操作組件并不是應(yīng)該經(jīng)常使用的工具。一般來說只是用來創(chuàng)建連續(xù)的動畫子漩,同時避免渲染組件結(jié)構(gòu)和同步太多視圖變化所帶來的大量開銷豫喧。setNativeProps是一個“簡單粗暴”的方法,它直接在底層(DOM幢泼、UIView等)而不是React組件中記錄state,這樣會使代碼邏輯難以理清紧显。所以,我們建議先嘗試用setState和shouldComponentUpdate方法來解決問題缕棵。
setNativeProps與TouchableOpacity
TouchableOpacity這個組件就在內(nèi)部使用了setNativeProps
方法來更新其子組件的透明度:
setOpacityTo: function(value) {
// Redacted: animation related code
this.refs[CHILD_REF].setNativeProps({
opacity: value
});
},
由此我們可以寫出下面這樣的代碼:子組件可以響應(yīng)點(diǎn)擊事件孵班,更改自己的透明度。而子組件自身并不需要處理這件事情挥吵,也不需要在實現(xiàn)中做任何修改重父。
<TouchableOpacity onPress={this._handlePress}>
<View style={styles.button}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
如果不使用setNativeProps
這個方法來實現(xiàn)這一需求花椭,那么一種可能的辦法是把透明值保存到state中忽匈,然后在onPress
事件觸發(fā)時更新這個值:
getInitialState() {
return { myButtonOpacity: 1, }
},
render() {
return (
<TouchableOpacity onPress={() => this.setState({myButtonOpacity: 0.5})}
onPressOut={() => this.setState({myButtonOpacity: 1})}>
<View style={[styles.button, {opacity: this.state.myButtonOpacity}]}>
<Text>Press me!</Text>
</View>
</TouchableOpacity>
)
}
比起之前的例子,這一做法會消耗大量的計算 —— 每一次透明值變更的時候React都要重新渲染組件結(jié)構(gòu)矿辽,即便視圖的其他屬性和子組件并沒有變化丹允。一般來說這一開銷也不足為慮郭厌,但當(dāng)執(zhí)行連續(xù)的動畫以及響應(yīng)用戶手勢的時候,只有正確地優(yōu)化組件才能提高動畫的流暢度雕蔽。
如果你看過NativeMethodsMixin.js中的setNativeProps
方法的實現(xiàn)折柠,你就會發(fā)現(xiàn)它實際是對RCTUIManager.updateView
的封裝 —— 而這正是重渲染所觸發(fā)的函數(shù)調(diào)用,具體可以參看ReactNativeBaseComponent.js中的receiveComponent.
復(fù)合組件與setNativeProps
復(fù)合組件并不是單純的由一個原生視圖構(gòu)成批狐,所以我們不能直接使用setNativeProps扇售。我們可以嘗試這樣去理解:如果是通過React.createClass方法自定義了一個組件,直接給它設(shè)置樣式prop是不會生效的嚣艇,你得把樣式props層層向下傳遞給子組件承冰,直到子組件是一個能夠直接定義樣式的原生組件。同理食零,我們也需要把setNativeProps傳遞給由原生組件封裝的子組件困乒。
將setNativeProps傳遞給子組件
具體的做法就是在我們的自定義組件中再封裝一個setNativeProps
方法,它的內(nèi)容為對合適的子組件調(diào)用真正的setNativeProps
方法贰谣,并傳遞要設(shè)置的參數(shù)娜搂。
var MyButton = React.createClass({
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps);
},
render() {
return (
<View ref={component => this._root = component} {...this.props}>
<Text>{this.props.label}</Text>
</View>
)
},
});
現(xiàn)在可以在TouchableOpacity
中嵌入MyButton
了!
我們在向下傳遞props時使用了{...this.props}
語法(這一用法的說明請參考對象的擴(kuò)展運(yùn)算符)吱抚。這是因為TouchableOpacity
本身其實也是個復(fù)合組件百宇, 它除了要求在子組件上執(zhí)行setNativeProps
以外,還要求子組件對觸摸事件進(jìn)行處理秘豹。因此恳谎,它會傳遞多個props,其中包含了onmoveshouldsetresponder 函數(shù)憋肖,這個函數(shù)需要回調(diào)給TouchableOpacity
組件因痛,以完成觸摸事件的處理。與之相對的是TouchableHighlight
組件岸更,它本身是由原生視圖構(gòu)成鸵膏,因而只需要我們實現(xiàn)setNativeProps
。
setNativeProps與shouldComponentUpdate
通過使用shouldComponentUpdate方法怎炊,可以避免重新渲染那些實際沒有發(fā)生變化的子組件所帶來的額外開銷谭企,此時使用setState
的性能已經(jīng)可以與setNativeProps
媲美了。