公司打算用
react-native
開發(fā)APP匆帚,初始RN遇到了很多坑谴咸,搭建了一個小的項目框架,結(jié)合redux
根據(jù)公司現(xiàn)成的接口寫了幾個小demo卷谈,接觸前端半年多杯拐,之前是做iOS的,感覺轉(zhuǎn)起來很困難世蔗,希望有大神可以給出些優(yōu)化的建議端逼!
項目介紹
- 這是一個利用
react-native
配合redux
開發(fā)的小框架。 - 項目主要結(jié)構(gòu)
-
android
安卓原生代碼 -
ios
iOS原生代碼 -
src
RN代碼-
actions
處理事件污淋,是把數(shù)據(jù)從應(yīng)用(譯者注:這里之所以不叫 view 是因為這些數(shù)據(jù)有可能是服務(wù)器響應(yīng)顶滩,用戶輸入或其它非 view 的數(shù)據(jù) )傳到 store 的有效載荷。它是 store 數(shù)據(jù)的唯一來源芙沥。 -
components
子組件 -
constants
常量诲祸,actions
中用到的狀態(tài),action
內(nèi)必須使用一個字符串類型的type
字段來表示將要執(zhí)行的動作而昨。多數(shù)情況下救氯,type
會被定義成字符串常量。當(dāng)應(yīng)用規(guī)模越來越大時歌憨,建議使用單獨的模塊或文件來存放action
着憨。 -
containers
父組件,類似于MVC中的控制器务嫡, -
reducers
改變狀態(tài)甲抖,action
描述事件發(fā)生,通過reducers
改變狀態(tài)state
-
statics
資源(例如圖片) -
utils
工具方法 -
store
統(tǒng)一管理狀態(tài) -
index.html
html加載DOM -
root.js
RN入口
-
-
index.android.js
安卓程序的入口 -
index.ios.js
蘋果程序入口 -
package.json
配置文件
項目啟動流程
-
index.html
通過加載<div id="react-root"></div>
進(jìn)入root.js
<!DOCTYPE html>
<meta charset="utf-8">
<title>React Native for Web</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<div id="react-root"></div>
<script src="/bundle.js"></script>
root.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import App from './containers/App';
import configureStore from './store/configureStore';
class Root extends Component {
render() {
return (
<Provider store={configureStore()}>
<App />
</Provider>
);
}
}
export default Root;
-
App.js
設(shè)置一些啟動時需要做的事情心铃,renderScene
添加路由
import React, {Component} from 'react';
import { Navigator } from 'react-native';
import MainTabsView from './MainTabsView';
import BroswerView from './BroswerView';
import LoginView from './LoginView';
import CarDetailView from './CarDetailView'
import FindCarView from './FindCarView'
import FreePriceView from './FreePriceView'
import CarLifeView from './CarLifeView'
import SpecialCarView from './SpecialCarView'
const ROUTES = {
main_tabs_view: MainTabsView,
login_view:LoginView,
broswer_view: BroswerView,
car_detail_view:CarDetailView,
find_car_view:FindCarView,
free_price_view:FreePriceView,
car_life_view:CarLifeView,
special_car_view:SpecialCarView,
}
class App extends Component {
renderScene = (route, navigator) => {
let Scene = ROUTES[route.name];
console.log("app renderscene");
switch (route.name){
case 'main_tabs_view':
return <Scene navigator={navigator} tab={2}/>;
case 'login_view':
return <Scene navigator={navigator}/>;
case 'broswer_view':
return <Scene
url={route.url}
navigator={navigator}/>;
case 'car_detail_view':
return <Scene {...route.params} navigator={navigator}/>;
case 'find_car_view':
return <Scene navigator={navigator}/>;
case 'free_price_view':
return <Scene navigator={navigator}/>;
case 'car_life_view':
return <Scene navigator={navigator}/>;
case 'special_car_view':
return <Scene navigator={navigator}/>;
}
}
configureScene = (route, routeStack) => {
switch (route.name){
default:
return Navigator.SceneConfigs.PushFromRight;
}
}
render() {
return <Navigator
initialRoute={{name: 'login_view'}}
renderScene={this.renderScene}
configureScene={this.configureScene}/>
}
}
export default App;
效果展示
-
登錄
登錄 - 首頁 (redux數(shù)據(jù)流程的簡單介紹)
- 我們在組件生命周期
componentDidMount()
中進(jìn)行數(shù)據(jù)請求准谚。this.props.actions.getBannerSource({});
根據(jù)redux
在action
中處理事件。
componentDidMount() {
this.props.actions.getBannerSource({});
this.props.actions.getHotCarSource({});
this.props.actions.getFreePriceListSource({});
this.props.actions.getCarShowBannerSource({});
this.props.actions.getSpecialCarSource({});
}
- 此時數(shù)據(jù)流將會來到
action
中,根據(jù)狀態(tài)常量DATA_BANNER
去扣,處理事件柱衔,action中只處理事件,要想改變狀態(tài),通過receiveBannerPosts(banner, json)
方法去reducers
中改變狀態(tài)
//輪播圖
export function getBannerSource(item) {
console.log("getBannerSource");
return dispatch => {
//dispatch(requestPosts(item));
return fetch(API_BASE_URL+'/mobile/ad/findAllShowAdByMobile', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'sessionid': "hanwuqia"
},
body: JSON.stringify({"query":{"pagenum":10,"page":1}})
})
.then((response) => response.json())
.then((responseJson) => {
//console.log(responseJson);
if(responseJson.code == 0){
dispatch(receiveBannerPosts(responseJson.data.rows));
}
})
.catch((error) => {
console.error(error);
});
}
}
function receiveBannerPosts(banner, json) {
return {
type: DATA_BANNER,
banner,
}
}
- 當(dāng)數(shù)據(jù)流來到
reducer
時會通過剛才的狀態(tài)常量給狀態(tài)banner
賦值唆铐,這樣請求下來的數(shù)據(jù)進(jìn)入到狀態(tài)樹中哲戚。
export default function secondView(state ={
banner: [],
}, action) {
switch (action.type) {
case types.DATA_BANNER :
return Object.assign({}, state, {
banner: action.banner
});
default:
return state
}
}
- 這時在組件中得知狀態(tài)改變從而重修刷新
render
方法,填充數(shù)據(jù),這樣就獲得了輪播圖的數(shù)據(jù)艾岂,這里輪播圖我用了一個叫做react-native-viewpager
的第三方組件
function mapStateToProps(state) {
return {
banner: state.secondView.banner,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(SecondView);
- RN 中所有布局全部包在一個大的
View
中就好像h5中的盒子布局的div
類似顺少,如果有兩個大盒子會報錯const { } = this.props;
是es6語法獲得到這個組件的狀態(tài),通過這樣的方法<Banner banner={banner}></Banner>
傳給子組件王浴,每當(dāng)狀態(tài)改變時會自動刷新脆炎,進(jìn)而子組件內(nèi)容也進(jìn)行刷新。
render() {
const { banner ,hotCarList,freePriceList,carShowBanner,specialCar,navigator} = this.props;
return (
<View style={{ flex: 1, backgroundColor:'#EBEBEB'}}>
<TitleBar title="react-native-mobile"></TitleBar>
<ScrollView >
<Banner banner={banner}></Banner>
<ToolBar navigator={navigator}></ToolBar>
<Text style={styles.title}>免費看低價</Text>
<FreePriceList navigator={navigator} freePriceList={freePriceList}></FreePriceList>
<Text style={styles.title}>車主秀</Text>
<CarShowBanner carShowBanner={carShowBanner}></CarShowBanner>
<Text style={styles.title}>熱門推薦</Text>
<HotCarList hotCarList={hotCarList} navigator={navigator}></HotCarList>
</ScrollView>
</View>
)
}
首頁
首頁
- 找車模塊
- 找車的熱門選車模塊用到了RN中核心組件
ListView
的使用,這是一個分組的listView,dataSource
就是列表的數(shù)據(jù)源氓辣,根據(jù)官方文檔不同樣式的列表有不同的初始化傳參方式腕窥,這里只介紹分組的列表,項目中用到了很多各種各樣的listView
列表筛婉!所以說他是核心組件。renderRow
返回每行樣式癞松,renderSectionHeader
返回每組組頭爽撒,renderHeader
返回列表表頭,像我一樣做過iOS開發(fā)的朋友可能會覺得不得理解响蓉,就像我們的UITableView中的各種代理方法一樣硕勿,官網(wǎng)還有很多,很實用枫甲。
render(){
const { brand} = this.props;
var Arr = brand ,
sectionIDs =[],//所有區(qū)ID的數(shù)組
rowIDs =[];//行ID數(shù)組
for (let i in brand ) {
sectionIDs.push(i);
rowIDs.push(brand[i])
}
return(
<ListView//創(chuàng)建表源武,并設(shè)置返回section和cell的方法
dataSource={this.dataSource.cloneWithRowsAndSections(Arr,sectionIDs,rowIDs)}
renderRow={this.renderRow}
renderSectionHeader={this.renderSectionHeader}
renderHeader={this.renderHeader }
/>
)
}
//返回頭部視圖
renderHeader(){
var rowWidth = screenWidth/5;
return(
<View style={{width:screenWidth,flexDirection:'row',flexWrap:'wrap',height:160}}>
{
this.hotBrndArr.map((dic, i) => <TouchableOpacity key={i} style={{width:rowWidth,height:80}} onPress={() => {
this.selectBrand(dic)}}>
<View style={{backgroundColor:'white',justifyContent:'center',alignItems:'center',width:rowWidth,height:80}}>
<Image style={styles.imageStyle} source={{ uri: dic[1]}}/>
<Text>{dic[2]}</Text>
</View>
</TouchableOpacity>) // 單行箭頭函數(shù)無需寫return
}
</View>
)
}
//返回cell的方法
renderRow(rowData,sectionID,rowID,highlighRow){
return(
<TouchableOpacity key={rowID} onPress={() => {
this.selectBrand(rowID)}}>
<View style={styles.cellStyle}>
<Image style={styles.imageStyle} source={{ uri: rowID[2]}}/>
<Text style={{marginLeft:20}}>{rowID[1]}</Text>
</View>
</TouchableOpacity>
)
}
//返回section的方法
renderSectionHeader(sectionData,sectionID){
return(
<View style={styles.sectionStyle}>
<Text style={{marginLeft:10}}>{sectionID}</Text>
</View>
)
}
找車
- 篩選的時候有個一個點擊側(cè)滑彈出的功能,這是糾結(jié)我最久的一塊想幻,一開始我選擇使用了官方API中的
Animated
粱栖,動畫實現(xiàn)方式很簡單,但是動畫加上大量的數(shù)據(jù)請求脏毯,大量的UI操作闹究,導(dǎo)致程序在安卓機(jī)上卡的一逼,畢竟只有半年前端經(jīng)驗食店,js更是菜的自己都不想說渣淤,谷歌了好幾天,安卓機(jī)的性能優(yōu)化的總是不理想吉嫩,沒辦法价认,只能采用第三方組件react-native-drawer
。使用后再無性能問題自娩。
<Drawer
side="right"
type="overlay"
ref={(ref) => this._drawer = ref}
content={...}
tapToClose={true}
openDrawerOffset={0.2}
tweenHandler={(ratio) => ({main: { opacity:(2-ratio)/2 }})}
onClose={()=>{this.maskDidClose()}}
styles={{
drawer: { shadowColor: '#000000', shadowOpacity: 0.5, shadowRadius: 3},
main: {backgroundColor:"#EBEBEB"},
}}
>
-
react-native-drawer
文檔中給出了各種方向用踩,各種樣子的側(cè)滑,感覺非常好用,下面是代碼滑進(jìn)滑出的方法
closeControlPanel = () => {
this._drawer.close()
};
openControlPanel = () => {
this._drawer.open()
};
找車篩選
- 免費看低價
- 這個模塊中讓我也遇到了很多的困難,首先類似
UICollectionView
中的布局其實也是個listView
,通過設(shè)置contentContainerStyle
讓他變成方形向下平鋪捶箱,運行時總是報警告說我的組頭是空的智什,然后enableEmptySections = {true}
設(shè)置這個屬性解決,最蛋疼的是有時候數(shù)據(jù)雖然請求下來但是現(xiàn)實空白頁丁屎,用手碰一下就會現(xiàn)實數(shù)據(jù)荠锭,通過設(shè)置這個屬性來解決removeClippedSubviews={false}
render(){
const { car,isRefreshing} = this.props;
return(
<ListView //創(chuàng)建ListView
dataSource={this.dataSource.cloneWithRows(car)} //設(shè)置數(shù)據(jù)源
renderRow={this.renderRow} //設(shè)置cell
contentContainerStyle={styles.listViewStyle}//設(shè)置cell的樣式
onEndReached={ this._toEnd }
onEndReachedThreshold={10}
renderFooter={ this._renderFooter }
enableEmptySections = {true}
removeClippedSubviews={false}
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={this._onRefresh}
tintColor="gray"
title="Loading..."
titleColor="gray"
colors={['#ff0000', '#00ff00', '#0000ff']}
progressBackgroundColor="#ffff00"
/>}
/>)
}
- 這個是RN自帶的下拉刷新,通過設(shè)置
title,colors
等設(shè)置下拉刷新的樣子晨川,通過設(shè)置refreshing
這個bool屬性來控制刷新開始結(jié)束
refreshControl={
<RefreshControl
refreshing={isRefreshing}
onRefresh={this._onRefresh}
tintColor="gray"
title="Loading..."
titleColor="gray"
colors={['#ff0000', '#00ff00', '#0000ff']}
progressBackgroundColor="#ffff00"
/>}
- 當(dāng)你發(fā)現(xiàn)你的cell點擊事件無效果時证九,或者你的下拉刷新的方法沒有走,是因為你賦給
ListView
的方法需要聲明一下共虑,這樣才能進(jìn)入到點擊事件中如:
constructor(props) {
super(props);
//返回cell樣式的方法
this.renderRow = this.renderRow.bind(this);
//下拉刷新的方法
this._onRefresh = this._onRefresh.bind(this);
//上滑刷新的方法
this._toEnd = this._toEnd.bind(this);
//返回底部視圖的方法
this._renderFooter = this._renderFooter.bind(this);
//數(shù)據(jù)源初始化
this.dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
});
}
免費看低價
免費看低價篩選
- 車生活
- 這個模塊是我們很常用的一個架構(gòu)愧怜,類似與網(wǎng)易新聞架構(gòu),是APP開發(fā)中非常常見的的一中架構(gòu)妈拌,首先當(dāng)然我還是嘗試著自己寫拥坛,根據(jù)按鈕點解設(shè)置
scrollView
的contentOffset
,根據(jù)contentOffset
設(shè)置應(yīng)該選中的按鈕尘分。以及根據(jù)切換設(shè)置橙色view
線的滑動猜惋,結(jié)果遇到了兩個問題,一個是向上面那樣培愁,大量數(shù)據(jù)加載著摔,大量的UI創(chuàng)建導(dǎo)致界面卡頓非常厲害,當(dāng)然是在安卓機(jī)上定续,我大蘋果肯定沒有這個問題谍咆,還有一個就是有些方法只有iOS可以試用,想寫一個兩端通用的更是難上加難,所以我引入了react-native-scrollable-tab-view
這個第三方組件
render(){
const {data,refresh,actions}=this.props;
return(
<ScrollableTabView style = {{width:screenWidth,height:screenHeight-64,backgroundColor:'#EBEBEB'}}
initialPage={0}
tabBarTextStyle={{fontSize: 14}}
tabBarUnderlineStyle={{backgroundColor: 'orange'}}
tabBarInactiveTextColor = "#999999" tabBarBackgroundColor = "white" tabBarActiveTextColor = "#333333"
onChangeTab={(obj) => this.changeTab(obj)}
>
<CarLifeList tabLabel='全部' actions={actions} pid={2} index={0} refresh ={refresh} dataArr={data}></CarLifeList>
<CarLifeList tabLabel='新車' actions={actions} pid={2} index={1} refresh ={refresh} dataArr={data}></CarLifeList>
<CarLifeList tabLabel='裝飾' actions={actions} pid={2} index={2} refresh ={refresh} dataArr={data}></CarLifeList>
<CarLifeList tabLabel='改裝' actions={actions} pid={2} index={3} refresh ={refresh} dataArr={data}></CarLifeList>
<CarLifeList tabLabel='自駕' actions={actions} pid={2} index={4} refresh ={refresh} dataArr={data}></CarLifeList>
</ScrollableTabView>
)
}
- 在這個界面我還遇到了一個我至今還無法相同的問題,我用
redux
管理狀態(tài)奶躯,我把一個數(shù)組的數(shù)據(jù)當(dāng)成一個狀態(tài),每次請求數(shù)據(jù)的時候?qū)?shù)組進(jìn)行操作港粱,上滑的時候向數(shù)組中添加數(shù)據(jù),我認(rèn)為數(shù)組中數(shù)據(jù)增加了就是狀態(tài)改變了旦签,render
理應(yīng)重新渲染才對查坪,但是顯然不是這樣的,我感覺有時候數(shù)組作為狀態(tài)發(fā)生改變時宁炫,redux
并不能檢測到偿曙,通過打印日志,數(shù)據(jù)確實發(fā)生改變了羔巢,但是確實沒有重新刷新望忆。之前我做vue
使用vuex
時也遇到過罩阵。我采用的方法不知道是不是規(guī)范的方法,我是在狀態(tài)中又添加了一個布爾的loading
,刷新時設(shè)置為ture
請求我數(shù)據(jù)設(shè)置為false
启摄,通過這個布爾值刷新列表進(jìn)行重新渲染稿壁。
//通過loading 的改變刷新
case types.CAR_SHOW_FETCH :
return Object.assign({}, state, {
carShowDataArr: action.carShowDataArr,
loading:action.loading
});
- 這個模塊還遇到個性能問題是有時候狀態(tài)太多,有的狀態(tài)改變并不需要刷新歉备,這時候基礎(chǔ)很重要了傅是,組件的生命周期有這么個方法
shouldComponentUpdate(nextProps, nextState) {}
當(dāng)這個方法的返回值是YES
時會刷新,NO
時不會刷新蕾羊,render
每次刷新之前都會調(diào)用這個方法喧笔,只有返回值是YES
時才會刷新,這個方法中我們可以做很多事情龟再,解決很多性能問題
車生活 - 車款詳情
- 這個界面算是比較復(fù)雜的界面书闸,想想要是讓我用原生寫,我估計要好久可能也寫不好利凑,尤其是下面顏色選擇浆劲,這就體現(xiàn)出H5布局的優(yōu)勢了,簡單哀澈,快梳侨,
react-native
使用flexBox
布局,真心簡單方便日丹,不過這個界面也遇到了一點性能的小問題,每當(dāng)每個色塊點擊時要重新請求數(shù)據(jù)蚯嫌,改變上面的圖片哲虾,也就是車的顏色,當(dāng)我的安卓機(jī)每次點擊切換時择示,TouchableOpacity
按鈕自帶的淡入淡出的效果變得非呈眨卡頓了,在onPress執(zhí)行了一個setState的操作栅盲,這個操作需要大量計算工作并且導(dǎo)致了掉幀汪诉。對此的一個解決方案是將onPress處理函數(shù)中的操作封裝到requestAnimationFrame中:
requestAnimationFrame(() => {
this.setState({
selectInteriorColor :index,
});
const { interiorColorList,exteriorColorList,actions ,id,detailType} = this.props;
let inId = interiorColorList[index].id;
let outId = exteriorColorList[this.state.selectExteriorColor].id;
actions.getCarInfo({outId,inId,id,detailType});
});
車款詳情
- RN 中加載web
-
這是個webView,這是我純屬顯得蛋疼想用reactNative加載個h5頁面看看啥效果谈秫,請見諒
WebView
性能優(yōu)化
- 學(xué)習(xí)了一段時間馬上就要開發(fā)了扒寄,感覺當(dāng)前對于我來說最大的問題還是關(guān)于性能的問題,因為前端基礎(chǔ)比較差拟烫,很多很簡單的東西需要好久才能找到合適的解決方案该编,總結(jié)了幾個常見的性能問題,之后仔細(xì)又閱讀了一遍官方的文檔硕淑,發(fā)現(xiàn)很多問題文檔上都有講课竣,所以文檔還是要臣问辏看啊
- console.log語句
- 在運行打好了離線包的應(yīng)用時,控制臺打印語句可能會極大地拖累JavaScript線程
- 解決方案發(fā)于樟,自己封裝一個打印語句公条,根據(jù)debug是0還是1選擇是否打印,方便我們上線時把打印全都去掉迂曲,推薦一個好用的第三方
redux-logger
- 開發(fā)模式和生產(chǎn)模式是大不相同的靶橱,有時候開發(fā)模式下會很卡,但生產(chǎn)模式就不一樣了奢米。
-
Navigator
導(dǎo)航切換抓韩,這個是非常常見的卡頓,可以選擇的解決方法也有很多鬓长,這是我的解決方法,利用官方推薦的這個組件InteractionManager
- 首先設(shè)置這樣一個狀態(tài)
onstructor(props) {
super(props);
this.state={
renderPlaceholderOnly:true,
}
}
-
render
方法中進(jìn)行判斷谒拴,renderPlaceholderOnly
為ture時給他一個加載頁面顯示false時顯示界面
render() {
if (this.state.renderPlaceholderOnly) {
//loading頁
return this._renderPlaceholderView();
}
return (
//界面
)
}
_renderPlaceholderView() {
return (
<View style={{flex:1,backgroundColor:'white',justifyContent:'center',alignItems:'center',}}>
<Text>Loading...</Text>
</View>
);
}
- 最后將請求數(shù)據(jù)的方法封裝到下面的方法中
InteractionManager.runAfterInteractions
是在js動畫結(jié)束時會走里面的回調(diào)。
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
this.setState({renderPlaceholderOnly: false});
this.props.actions.getBrandSource({});
this.props.actions.getCarTypesource();
});
}
- 關(guān)于
listView
的性能優(yōu)化 -
initialListSize
這個屬性定義了在首次渲染中繪制的行數(shù)涉波。如果我們關(guān)注于快速的顯示出頁面英上,可以設(shè)置initialListSize
為1,然后我們會發(fā)現(xiàn)其他行在接下來的幀中被快速繪制到屏幕上啤覆。而每幀所顯示的行數(shù)由pageSize
所決定 -
pageSize
在初始渲染也就是initialListSize被使用之后苍日,ListView將利用pageSize來決定每一幀所渲染的行數(shù)。默認(rèn)值為1 —— 但是如果你的頁面很小窗声,而且渲染的開銷不大的話相恃,你會希望這個值更大一些。稍加調(diào)整笨觅,你會發(fā)現(xiàn)它所起到的作用拦耐。 -
scrollRenderAheadDistance
在將要進(jìn)入屏幕區(qū)域之前的某個位置,開始繪制一行见剩,距離按像素計算杀糯。如果我們有一個2000個元素的列表,并且立刻全部渲染出來的話苍苞,無論是內(nèi)存還是計算資源都會顯得很匱乏固翰。還很可能導(dǎo)致非常可怕的阻塞羹呵。因此scrollRenderAheadDistance允許我們來指定一個超過視野范圍之外所需要渲染的行數(shù)骂际。 -
removeClippedSubviews
當(dāng)這一選項設(shè)置為true的時候,超出屏幕的子視圖(同時overflow
值為hidden)會從它們原生的父視圖中移除冈欢。這個屬性可以在列表很長的時候提高滾動的性能方援。默認(rèn)為false。這是一個應(yīng)用在長列表上極其重要的優(yōu)化涛癌。Android上犯戏,overflow值總是hidden的送火,所以你不必?fù)?dān)心沒有設(shè)置它。而在iOS上先匪,你需要確保在行容器上設(shè)置了overflow: hidden种吸。 - 如果你正在使用一個ListView,你必須提供一個rowHasChanged函數(shù)呀非,它通過快速的算出某一行是否需要重繪坚俗,來減少很多不必要的工作。如果你使用了不可變的數(shù)據(jù)結(jié)構(gòu)岸裙,這項工作就只需檢查其引用是否相等猖败。同樣的,你可以實現(xiàn)
shouldComponentUpdate
函數(shù)來指明在什么樣的確切條件下降允,你希望這個組件得到重繪恩闻。 - 關(guān)于動畫
Animated
的使用,盡量使用LayoutAnimation
,Animated
的接口一般會在JavaScript
線程中計算出所需要的每一個關(guān)鍵幀,而LayoutAnimation
則利用了Core Animation
剧董,使動畫不會被JS線程和主線程的掉幀所影響幢尚。尤其是在動畫過程中有大量的數(shù)據(jù)請求,狀態(tài)改變翅楼。 - 當(dāng)具有透明背景的文本位于一張圖片上時尉剩,或者在每幀重繪視圖時需要用到透明合成的任何其他情況下,這種現(xiàn)象尤為明顯毅臊。設(shè)置shouldRasterizeIOS或者renderToHardwareTextureAndroid屬性可以顯著改善這一現(xiàn)象理茎。 注意不要過度使用該特性,否則你的內(nèi)存使用量將會飛漲管嬉。在使用時功蜓,要評估你的性能和內(nèi)存使用情況。如果你沒有需要移動這個視圖的需求宠蚂,請關(guān)閉這一屬性。
- 在iOS上童社,每次調(diào)整Image組件的寬度或者高度求厕,都需要重新裁剪和縮放原始圖片。這個操作開銷會非常大扰楼,尤其是大的圖片呀癣。比起直接修改尺寸,更好的方案是使用transform: [{scale}]的樣式屬性來改變尺寸弦赖。比如當(dāng)你點擊一個圖片项栏,要將它放大到全屏的時候,就可以使用這個屬性蹬竖。
- Touchable系列組件不能很好的響應(yīng)
- 有些時候沼沈,如果我們有一項操作與點擊事件所帶來的透明度改變或者高亮效果發(fā)生在同一幀中流酬,那么有可能在onPress函數(shù)結(jié)束之前我們都看不到這些效果。比如在onPress執(zhí)行了一個setState的操作列另,這個操作需要大量計算工作并且導(dǎo)致了掉幀芽腾。對此的一個解決方案是將onPress
處理函數(shù)中的操作封裝到requestAnimationFrame
中
- Demo地址:
- git( https://github.com/heiheiLqq/RNBaseApp.git )