はじめに
こんにちは、React, ReactNativeでWebとアプリの開発を行っております、株式会社Lyactの山田と申します。
普段は音声小説配信サービスWritoneというアプリの開発を行っております。
今回は、アプリの分析を行うために導入したscreentrackingでかなり手こずったところがあったので、
それについて書きます。
色々わからないことも多いため、ご指摘・ご指導いただけるとありがたいです。
どんな問題?
これは、公式ドキュメントのScreen trackingの方法
上記を見ていただくとわかるのですが、
react nativeで、ScreenTrackingを行う場合は、
import { GoogleAnalyticsTracker } from 'react-native-google-analytics-bridge';
const tracker = new GoogleAnalyticsTracker(GA_TRACKING_ID);
// gets the current screen from navigation state
function getActiveRouteName(navigationState) {
if (!navigationState) {
return null;
}
const route = navigationState.routes[navigationState.index];
// dive into nested navigators
if (route.routes) {
return getActiveRouteName(route);
}
return route.routeName;
}
const NavigatorA = createStackNavigator(NavigatorAConfigs);
// export default NavigatorAではなく、 () => <NavigatorA />という形になる
export default () => (
<NavigatorA
onNavigationStateChange={(prevState, currentState) => {
const currentScreen = getActiveRouteName(currentState);
const prevScreen = getActiveRouteName(prevState);
if (prevScreen !== currentScreen) {
tracker.trackScreenView(currentScreen);
}
}}
/>
);
こんな感じで、普通のコンポーネントをexportするのではなく、
それを関数化(?)して、export defaultする形になります。
しかし、自分が作っているアプリの構成は
このNavigatorAの上に
RouteNavigatorがいて、
同階層にNavigatorB、NavigatorCがいるという構成でした。
すると、Navigator間の遷移(例えば、PageA1から、PageB1に移るなど)が、できなくなってしまったのです!!
解決策
結論としては、上位ルーターののnavigationをcallbackでいつでも呼び出せるようにしておけば、解決します。
まず、下のように、Initialというコンポーネントを作ります
・・・
import NavigateListener from './lib/NavigationListener'
・・・
export default class Initial extends Component {
componentDidMount = async () => {
const { navigation } = this.props
// とりあえず、ここのnavigationをcallbackにいれておく。
NavigateListener.setTopRouting((navigator) => navigation.navigate(navigator))
// 入れ終わったらNavigatorAに遷移しとく
navigation.navigate('navigatorA')
}
render() {
return (
<View></View>
)
}
}
ここのポイントは、NavigationListenerのsetChangeActionに、callbackを送っていることです。
このNavigationListenerは、
class NavigateListener {
// 関数をセットしておく
setTopRouting = (callback) => {
this.topRouting = callback
}
// これであらかじめセットしていた関数を発火
topRouting = (navigato) => {
this.topRouting(navigator)
}
}
export default new NavigateListener()
というシンプルな作りになっていて、
callbackでsetした関数を、NavigateListener.topRouting('{navigator名}')
で呼び出せるようになっています!
これで、例えば、pageA1から、pageB1に遷移したい場合は、
・・・
import NavigationListener from './lib/NavigationListener'
・・・
export default class PageA extends React.Component{
・・・
render(){
return(
・・・
<div onPress={()=> NavigationListener.topRouting('NavigatorB')>NavigatorBへ</div>
・・・
)
}
・・・
}
こんな感じにすればいけます。
以上です。
ちなみに、このcallbackを使って他のコンポーネントで呼び出すという処理は、
とても便利ですが、多用すると複雑になってしまうので、ほどほどに使うと良いかもです
ちなみに、なぜ () => の形にしたら
上位Routerを跨げなくなったのかは、わかっておりません笑
教えていただけると幸いです。