title: 翻譯|React-navigation導(dǎo)航系統(tǒng)(3)-高級指南
date: 2017-03-29 16:41:19
categories: 翻譯
tags: React-Native
Redux Intergration
為了在redux中處理app的navigation state,你可以傳遞你自己的navigation prop到一個navigator.你的navigation prop必須提供當(dāng)前的state,還有就是處理navigation配置項的dispatcher.
使用redux,你的app state由reducer來定義.每一個navigation router都有一個reducer,叫做getStateForAction.下面是一在redux應(yīng)用中使用navigators的簡單實例:
import { addNavigationHelpers } from 'react-navigation';
const AppNavigator = StackNavigator(AppRouteConfigs);
const navReducer = (state, action) => {
const newState = AppNavigator.router.getStateForAction(action, state);
return newState || state;
};
const appReducer = combineReducers({
nav: navReducer,
...
});
@connect(state => ({
nav: state.nav,
}))
class AppWithNavigationState extends React.Component {
render() {
return (
<AppNavigator navigation={addNavigationHelpers({
dispatch: this.props.dispatch,
state: this.props.nav,
})} />
);
}
}
const store = createStore(appReducer);
class App extends React.Component {
render() {
return (
<Provider store={store}>
<AppWithNavigationState />
</Provider>
);
}
}
一旦按照實例操作,navigation state就存儲在redux的store中,這樣就可以使用redux的dispatch函數(shù)來發(fā)起navigation的actions.
牢記在心,當(dāng)一個navigator給定一個navigationprop,他將失去內(nèi)部state的控制權(quán).這意味著現(xiàn)在你來負(fù)責(zé)state的持久化,處理任何的深度鏈接,整合Back按鈕等操作.
當(dāng)你的navigator是巢式的時候,Navigation state自動從一個navigator傳遞到另一個navigator.注意,為了讓子代navigator可以從父代navigator接收state,它應(yīng)該定義為一個screen.
對應(yīng)上面的實例,你可以定義AppNavigator包含一個巢式的TabNavigator:
const AppNavigator = StackNavigator({
Home: { screen: MyTabNavigator },
});
在這個實例中,一旦你在AppWithNavigationState中connect AppNavigator到Redux,MyTabNavigation將會自動接入到navigation state 作為navigtion的prop.
Web Integration
React Navigation routers工作在web環(huán)境下允許你和原生app共享導(dǎo)航的邏輯.綁定在react-navigation的視圖目前只能工作在React Native下,但是在react-primitives項目中可能會有所改變.
示例程序
這個網(wǎng)站由React Navigation構(gòu)建,使用了createNavigation和TabRouter.
看看網(wǎng)站的源代碼app.js
app如何獲得渲染參看server.js.在瀏覽器中,使用[BrowserAppContainer.js]來喚醒和獲得渲染.
更多內(nèi)容,很快呈現(xiàn)
不久會有詳細(xì)的教程.
Deep Linking
這一部分指南中,我們將設(shè)置app來處理外部URIs.讓我們從SimpleApp開始
getting start的指南
在這個示例中,我們想使用類似mychat://chat/Taylor的URI來打開我們的app,直接連接到Taylor的chat page.
Configuration
在前面我們定義了navigator想下面這樣:
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: { screen: ChatScreen },
});
我們想讓path類似chat/Taylor鏈接到“Chat”screen,傳遞user作為參數(shù).我們重新定義我們的chat screen使用一個path來告訴router需要匹配的path和需要提取的參數(shù).這個路徑配置為chat/:user.
const SimpleApp = StackNavigator({
Home: { screen: HomeScreen },
Chat: {
screen: ChatScreen,
path: 'chat/:user',
},
});
URI的前綴
下面配置navigation container來提取app的path.當(dāng)配置在頂層navigator上的時候,我們提供containerOperations,
const SimpleApp = StackNavigator({
...
}, {
containerOptions: {
// on Android, the URI prefix typically contains a host in addition to scheme
URIPrefix: Platform.OS == 'android' ? 'mychat://mychat/' : 'mychat://',
},
});
iOS
基于mychat://URI圖式配置原生的iOS app.
在SimpleApp/ios/SimpleApp/AppleDelegate.m
// Add the header at the top of the file:
#import <React/RCTLinkingManager.h>
// Add this above the `@end`:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
return [RCTLinkingManager application:application openURL:url
sourceApplication:sourceApplication annotation:annotation];
}
在Xcode里,打開項目的simpleApp/ios/SimpleApp.xcodeproj.在邊欄中選擇項目導(dǎo)航到info tab.向下滑動到“URL Types”并且添加一個.在新的URL type,設(shè)定名稱和url圖式對應(yīng)想導(dǎo)航到的url圖式.
現(xiàn)在可以在Xcode中點擊play,或者在命令行運(yùn)行
react-native run-ios
為了在iOS中測試URI,在safari中打開mychat://chat/Taylor
Android
為了在Andorid中鏈接外鏈,可以在manifest中創(chuàng)建一個新的intent.
在SimpleApp/android/app/src/main/AndroidManifest.xml中MainActivity內(nèi)添加新的VIEWtypeintent-filter.
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mychat"
android:host="mychat" />
</intent-filter>
現(xiàn)在,重新運(yùn)行:
react-native run-android
在Android中測試intent操作,運(yùn)行
adb shell am start -W -a android.intent.action.VIEW -d "mychat://mychat/chat/Taylor" com.simpleapp
Screen tracking and analytics
這個實例中展示怎么做屏幕追蹤并且發(fā)到Google Analytics.這個方法應(yīng)用在其他的移動分析SDK也是可以的.
Screen tracking
當(dāng)我們使用內(nèi)建的navigation container,我們使用onNavigationStateChange來追蹤screen.
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
const tracker = new GoogleAnalyticsTracker(GA_TRACKING_ID);
// gets the current screen from navigation state
function getCurrentRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getCurrentRouteName(route);
}
return route.routeName;
}
const AppNavigator = StackNavigator(AppRouteConfigs);
export default () => (
<AppNavigator
onNavigationStateChange={(prevState, currentState) => {
const currentScreen = getCurrentRouteName(currentState);
const prevScreen = getCurrentRouteName(prevState);
if (prevScreen !== currentScreen) {
// the line below uses the Google Analytics tracker
// change the tracker here to use other Mobile analytics SDK.
tracker.trackScreenView(currentScreen);
}
}}
/>
);
使用Redux做Screen tracking
使用Redux的時候,我們可以寫Redux 中間件來track screen.為了達(dá)到這個目的,我們從前面的部分重新使用getCurrenRouteName.
import { NavigationActions } from 'react-navigation';
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
const tracker = new GoogleAnalyticsTracker(GA_TRACKING_ID);
const screenTracking = ({ getState }) => next => (action) => {
if (
action.type !== NavigationActions.NAVIGATE
&& action.type !== NavigationActions.BACK
) {
return next(action);
}
const currentScreen = getCurrentRouteName(getState().navigation);
const result = next(action);
const nextScreen = getCurrentRouteName(getState().navigation);
if (nextScreen !== currentScreen) {
// the line below uses the Google Analytics tracker
// change the tracker here to use other Mobile analytics SDK.
tracker.trackScreenView(nextScreen);
}
return result;
};
export default screenTracking;
創(chuàng)建Redux store并應(yīng)用上面的中間件
在創(chuàng)建store的時候應(yīng)用這個screenTracking的中間件.看看Redux Integration了解細(xì)節(jié).
const store = createStore(
combineReducers({
navigation: navigationReducer,
...
}),
applyMiddleware(
screenTracking,
...
),
);