JavaScript
reactnative

react-navigationでページ遷移を検知して処理をはさむ

More than 1 year has passed since last update.

背景

  • react-navigationを使っていてページ遷移を契機に処理を実行したい
  • 例えば特定のページだけAndroidのバックボタンを制御したいようなときに、ページ遷移ではcomponentWillUnmount等通らないので解除するタイミングがない
    • 次のページのcomponentWillMountで解除してもいいが戻られた時に制御が外れてしまう

対応サンプル

  • react-navigationの機能でページ遷移を検知することができた
index.android.js
import React, { Component } from 'react';
import { AppRegistry } from 'react-native';
import AppNavigator, { disabledBackScreens } from './app/navigators/AppNavigator';
import { disabledAndroidBack, abledAndroidBack } from './app/utils/Util';

class ReactNativeSample extends Component {
  render() {
    // onNavigationStateChangeに渡す関数がページ遷移の度に呼ばれる
    return <AppNavigator onNavigationStateChange={this.onNavigationStateChange} />;
  }

  // 引数のサンプルは後述
  onNavigationStateChange(prevState, currentState, action) {
      // routesは遷移履歴の配列
    const routes = currentState.routes;
    // 現在の画面は配列の最後、routeNameで画面名がとれる
    const currentRouteName = routes[routes.length - 1].routeName;
    // ここの例では戻るを無効にしたい画面か判断しそれぞれ処理を呼んでいる
    disabledBackScreens.includes(currentRouteName) ? disabledAndroidBack() : abledAndroidBack();
  }
}

AppRegistry.registerComponent('ReactNativeSample', () => ReactNativeSample);
  • onNavigationStateChangeで受け取る引数のサンプル
  • スクリーンショット 2017-09-22 1.09.15.png
app/navigators/AppNavigator.js
import { StackNavigator } from 'react-navigation';
import SampleAScreen from '../containers/SampleAScreen';
import SampleBScreen from '../containers/SampleBScreen';
import SampleCScreen from '../containers/SampleCScreen';
import SampleDScreen from '../containers/SampleDScreen';
import SampleEScreen from '../containers/SampleEScreen';

const AppNavigator = StackNavigator({
  SampleA: { screen: SampleAScreen },
  SampleB: { screen: SampleBScreen },
  SampleC: { screen: SampleCScreen },
  SampleD: { screen: SampleDScreen },
  SampleE: { screen: SampleEScreen },
});

export const disabledBackScreens = ['SampleB', 'SampleD'];
export default AppNavigator;
app/utils/Util.js
import { BackHandler } from 'react-native'

// trueを返すとバックボタンを押した時のデフォルトの動きをキャンセルしてくれる
const androidBackHandler = () => true

export const disabledAndroidBack = () =>{
  BackHandler.addEventListener('hardwareBackPress', androidBackHandler)
}

export const abledAndroidBack = () =>{
  // 第二引数はaddEventListenerした時の第二引数と同じものでないとダメ
  BackHandler.removeEventListener('hardwareBackPress', androidBackHandler)
}

まとめ

  • ページ遷移の度に処理をかませることが出来るので何かと便利そう