(二)[APP開發(fā)-導航器與用戶登錄狀態(tài)]React Native 從零到構建Android與IOS應用發(fā)布

根據(jù)我的項目需要,其實我需要一個很簡單的APP應用,但就是這樣一個簡單的APP應用,我卻耗費了大量時間和精力,因為,坑實在太多了,我就把我遇到的坑寫出來做個記錄。

二、APP開發(fā)

我項目需要以下的頁面

一、主界面

二、登錄

三、個人中心

四、list

五、detail

由于APP與web不一樣,所以沒有URL的概念,相對應的是導航器,初入RN,也沒有使用原生的navigator組件,而是經(jīng)大神推薦查看了ant-design的組件Demo,依葫蘆畫瓢使用了 navigation組件。

1)Navigation組件

首先我們需要安裝 react-native-navigation

npm i -g react-navigation --save

注意,在ios下,所有安裝的npm包,都要yarn一下,主要是依賴的問題,否則會提示 安裝成功,但依賴失敗錯誤

命令:

yarn add react-native-navigation

安裝后,我們就可以使用了

navigation有很豐富的功能,具體可以到?https://reactnavigation.org/docs/navigators/?查看文檔

而我項目只需要使用到?StackNavigator 而沒有TabNavigator/DrawerNavigator導航,所以我只介紹?StackNavigator 和導航切換的方法

引入navigation組件

import { StackNavigator,TabNavigator,NavigationActions } from 'react-navigation';

配置導航

import Login from './Login' // 其他場景

const FirstApp = StackNavigator({?

?????????????????IndexScreen: {?

?????????????????????????screen: IndexScreen, // initialRouteName: 'IndexScreen' navigationOptions:({ navigation })=>({

????????????????????????????????????//headerTitle: '導航標題',headerLeft: () 可以設置 headerTitle headerLeft headerRight等,具體參考官方文檔

? ? ? ? ? ? ? ? ? ? ? ? ?})

? ? ? ? ? ? ? ? },

????????????????// 其他場景: {screen: 場景名稱},

????????????????Login:{screen: Login},

? ? ? ? ? ? ? ? ......

? ? ? ? },

????????{

? ? ? ? ? ? ? ? // ....這里是其他公共配置

? ? ? ? ? ? ? ? // 例如?initialRouteName?navigationOptions等,具體參考官方文檔或網(wǎng)上的navigation的配置資料

????????});

在Component中也可配置navigationOptions

static navigationOptions = ({navigation, screenProps}) => ({

????????headerTitle: '導航標題'

});


請注意,navigationOptions的配置優(yōu)先級為:

StackNavigator中的navigationOptions <?Component中的navigationOptions <?StackNavigator中的Screen的配置

會按優(yōu)先級進行覆蓋

然后是將組件加入APP的component

在registerComponent的component中

render() {?

?????????????return (

????????????????<FirstApp style={{backgroundColor:'#ffffff'}} ref={nav => { this.navigator = nav; }} />

????????????)

}

至此,navigation就配置完成,那么對應的支持的方法分為幾種

第一種,是常用的在子組件中調用

可以通過

this.props.navigation.navigate('Screen Name',{...params});?

進行跳轉或

this.props.navigation.goBack();

進行返回

第二種,在StackNavigator中的navigationOptions中使用

navigationOptions: ({navigation})=>({

? ? ? ? //...在headerLeft等組件的onPress方法中 ()=>{

? ? ? ? //? ? ? navigation.goBack();

? ? ? ? // 或

? ? ? ? //? ? ??navigation.navigate('Screen Name',{...params});

? ? ? ? // }

? ? ? ? // 請注意,在這里需要用到 TouchableOpacity 組件包括按鈕,touchablehighlight會報錯,請注意

});

還有一個特別值得注意的是,當你只有headerRight時,需要設定headerLeft為一個空的view,否則,會導致標題無法居中

headerLeft: (

? ? ? ? <View style={{height: 44,width: 55,paddingRight:15} }/>

)

第三種,在registerComponent 中調用導航方法,這里主要是我使用了極光PUSH所以會在監(jiān)聽時調用導航器,通過控制臺打印this對象發(fā)現(xiàn)了這個方法

this.navigator._navigation.navigate('Screen Name',{...params});

this.navigator._navigation.goBack();

至此,Navigation教程完成,相信你能配置一個符合你的導航器

2) 登錄權限驗證

然后就是User登錄判斷,我的需求是需要用戶登錄,那我APP就需要判斷,而又不應該使用cookie來進行處理,查閱了資料后,發(fā)現(xiàn)用戶登錄狀態(tài)判斷代碼,但有錯誤,會導致bundle報錯,所以我對此進行了修正

首先我們需要一個本地儲存引擎,我這里使用的是react-native-storage

用上面的npm方法進行安裝

npm i -g react-native-storage --save

yarn add?react-native-storage

資料上說官方并不推薦直接使用storage,所以我按教程封裝了一個storage方法放在storageUtil.js

var storage = new Storage({

????// 最大容量,默認值1000條數(shù)據(jù)循環(huán)存儲

????size: 1000,

????// 存儲引擎:對于RN使用AsyncStorage,對于web使用window.localStorage

????// 如果不指定則數(shù)據(jù)只會保存在內存中,重啟后即丟失

????storageBackend: AsyncStorage,

????// 數(shù)據(jù)過期時間,默認一整天(1000 * 3600 * 24 毫秒),設為null則永不過期

????defaultExpires: null,

????// 讀寫時在內存中緩存數(shù)據(jù)。默認啟用。

????enableCache: true,

// 如果storage中沒有相應數(shù)據(jù),或數(shù)據(jù)已過期,

// 則會調用相應的sync方法,無縫返回最新數(shù)據(jù)。

// sync方法的具體說明會在后文提到

// 你可以在構造函數(shù)這里就寫好sync的方法

// 或是寫到另一個文件里,這里require引入

// 或是在任何時候,直接對storage.sync進行賦值修改

//sync: require('./sync')? // 這個sync文件是要你自己寫的

})

// 然后設置全局對象,由于我是APP所以不存在web 輕應用,所以不需要用window.storage = storage;而是global.storage = storage;

global.storage = storage;

設置好后,我需要一個Global.js來判斷當用戶打開APP時是否登錄

//用戶登錄數(shù)據(jù)

global.user = {

????loginState:'',//登錄狀態(tài)

????userData:'',//用戶數(shù)據(jù)

};

//刷新的時候重新獲得用戶數(shù)據(jù)

storage.load({

????key: 'loginState',

}).then(ret => {

????global.user.loginState = true;

????global.user.userData = ret;

}).catch(err => {

????global.user.loginState = false;

????global.user.userData = '';

})

然后在registerComponent中import這兩個包,就完成了用戶的驗證



注意:但實際情況卻是,storage.load安卓下并未觸發(fā),我并不清楚這是什么情況引起的,但IOS下又觸發(fā)了,并且調試并未出現(xiàn)錯誤,所以我大膽猜測是import的時候,并未初始化完成storage,導致load方法并未實際執(zhí)行,可能這涉及到RN本身的機制,所以我又想了一個辦法,我封裝了一個SUser.js的全局方法,在每個組件的componentWillMount中進行驗證,當global.user.loginState==false時我就執(zhí)行清除用戶數(shù)據(jù)并返回登錄界面


import JPushModule from 'jpush-react-native';

var Suser = {

????phone:null,

????checklogin:function(t){

????if (!global.user.loginState) {

????????storage.load({

????????????key: 'loginState'

????????}).then(ret => {

????????????global.user.loginState = true;

????????????global.user.userData = ret;

????????????global.user.phone = ret.phone;

????????}).catch(err => {

????????????JPushModule.clearAllNotifications();

????????????global.user.loginState = false;

????????????global.user.userData = '';

????????????t.navigate('Login');

????????})

????}

},

logout:function(t){

????storage.remove({

????????key: 'loginState'

????});

????global.user.loginState = false;

????global.user.userData = '';

????JPushModule.clearAllNotifications();

????t.navigate('Login');

}

}

global.Suser = Suser;

這樣,就解決了用戶登錄判斷,雖然方法很笨,但有效,如有大神有更好的方法,請聯(lián)系我,感激不盡?。?!

還有注意:當你在chorme中查看console時,發(fā)現(xiàn)app init了2次或更多,導致所有事件都會執(zhí)行兩次,例如alert,那么只是模擬器問題,關閉APP,重新啟動就好了,原因我不清楚,偶爾會出現(xiàn)重復2次或3次或4次,調試了很久也沒解決,正式包不存在這個問題,問了大神也不清楚,代碼并未有問題。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容