LoginSignup
3
0

More than 5 years have passed since last update.

React-navigationで、screen trackingしてて、上位のルーターを跨げなくなったときの対処法

Posted at

はじめに

こんにちは、React, ReactNativeでWebとアプリの開発を行っております、株式会社Lyactの山田と申します。

普段は音声小説配信サービスWritoneというアプリの開発を行っております。

今回は、アプリの分析を行うために導入したscreentrackingでかなり手こずったところがあったので、
それについて書きます。

色々わからないことも多いため、ご指摘・ご指導いただけるとありがたいです。

どんな問題?

これは、公式ドキュメントのScreen trackingの方法
上記を見ていただくとわかるのですが、

react nativeで、ScreenTrackingを行う場合は、

navigatorA.js
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がいるという構成でした。
スクリーンショット 2019-01-24 10.06.38.png

すると、Navigator間の遷移(例えば、PageA1から、PageB1に移るなど)が、できなくなってしまったのです!!

解決策

結論としては、上位ルーターののnavigationをcallbackでいつでも呼び出せるようにしておけば、解決します。

まず、下のように、Initialというコンポーネントを作ります
スクリーンショット 2019-01-24 10.18.40.png

Initial.js

・・・
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は、

NavigationListener.js
class NavigateListener {

    // 関数をセットしておく
  setTopRouting = (callback) => {
    this.topRouting = callback
  }

    // これであらかじめセットしていた関数を発火
  topRouting = (navigato) => {
    this.topRouting(navigator)
  }
}

export default new NavigateListener()

というシンプルな作りになっていて、
callbackでsetした関数を、NavigateListener.topRouting('{navigator名}')
で呼び出せるようになっています!

これで、例えば、pageA1から、pageB1に遷移したい場合は、

NavigatorA.js
・・・
import NavigationListener from './lib/NavigationListener'
・・・

export default class PageA extends React.Component{
・・・
render(){
 return(
  ・・・
   <div onPress={()=> NavigationListener.topRouting('NavigatorB')>NavigatorBへ</div>
    ・・・
 )
}
・・・
}

こんな感じにすればいけます。

以上です。
ちなみに、このcallbackを使って他のコンポーネントで呼び出すという処理は、
とても便利ですが、多用すると複雑になってしまうので、ほどほどに使うと良いかもです

ちなみに、なぜ () => の形にしたら
上位Routerを跨げなくなったのかは、わかっておりません笑

教えていただけると幸いです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0