Skip to content

Commit

Permalink
Introduce custom remove action to cleanup dismissed screens. (#390)
Browse files Browse the repository at this point in the history
This change introduces REMOVE custom navigation command to be used for navigation wrapper. This command works similarily to POP however it does not pop views on top of the one passed as a key. It is important that when view is dismissed we only remove that screen from the stack and not accidently remove other views that might've been added on top in the meantime.
  • Loading branch information
kmagiera committed Feb 26, 2020
1 parent d2072d2 commit 2ccb75f
Showing 1 changed file with 44 additions and 9 deletions.
53 changes: 44 additions & 9 deletions createNativeStackNavigator.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import { StyleSheet } from 'react-native';
import {
StackRouter,
SceneView,
StackActions,
createNavigator,
} from '@react-navigation/core';
import { createKeyboardAwareNavigator } from '@react-navigation/native';
import { HeaderBackButton } from 'react-navigation-stack';
import {
ScreenStack,
Expand All @@ -25,9 +24,14 @@ function renderComponentOrThunk(componentOrThunk, props) {
return componentOrThunk;
}

const REMOVE_ACTION = 'NativeStackNavigator/REMOVE';

class StackView extends React.Component {
_removeScene = route => {
this.props.navigation.dispatch(StackActions.pop({ key: route.key }));
this.props.navigation.dispatch({
type: REMOVE_ACTION,
key: route.key,
});
};

_onAppear = (route, descriptor) => {
Expand Down Expand Up @@ -207,6 +211,11 @@ class StackView extends React.Component {
style={[StyleSheet.absoluteFill, options.cardStyle]}
stackAnimation={stackAnimation}
stackPresentation={stackPresentation}
pointerEvents={
index === this.props.navigation.state.routes.length - 1
? 'auto'
: 'none'
}
gestureEnabled={
options.gestureEnabled === undefined ? true : options.gestureEnabled
}
Expand Down Expand Up @@ -243,13 +252,39 @@ const styles = StyleSheet.create({

function createStackNavigator(routeConfigMap, stackConfig = {}) {
const router = StackRouter(routeConfigMap, stackConfig);
// Create a navigator with StackView as the view
let Navigator = createNavigator(StackView, router, stackConfig);
// if (!stackConfig.disableKeyboardHandling) {
// Navigator = createKeyboardAwareNavigator(Navigator, stackConfig);
// }

return Navigator;
// belowe we override getStateForAction method in order to add handling for
// a custom native stack navigation action. The action REMOVE that we want to
// add works in a similar way to POP, but it does not remove all the routes
// that sit on top of the removed route. For example if we have three routes
// [a,b,c] and call POP on b, then both b and c will go away. In case we
// call REMOVE on b, only b will be removed from the stack and the resulting
// state will be [a, c]
const superGetStateForAction = router.getStateForAction;
router.getStateForAction = (action, state) => {
if (action.type === REMOVE_ACTION) {
const { key, immediate } = action;
let backRouteIndex = state.index;
if (key) {
const backRoute = state.routes.find(route => route.key === key);
backRouteIndex = state.routes.indexOf(backRoute);
}

if (backRouteIndex > 0) {
const newRoutes = [...state.routes];
newRoutes.splice(backRouteIndex, 1);
return {
...state,
routes: newRoutes,
index: newRoutes.length - 1,
isTransitioning: immediate !== true,
};
}
}
return superGetStateForAction(action, state);
};
// Create a navigator with StackView as the view
return createNavigator(StackView, router, stackConfig);
}

export default createStackNavigator;

0 comments on commit 2ccb75f

Please sign in to comment.