diff --git a/example/StackNavigator.tsx b/example/StackNavigator.tsx index 3df29622..c53fc399 100644 --- a/example/StackNavigator.tsx +++ b/example/StackNavigator.tsx @@ -228,6 +228,10 @@ const StackRouter: Router = { }; }, + shouldActionPropagateToChildren(action) { + return action.type === 'NAVIGATE'; + }, + shouldActionChangeFocus(action) { return action.type === 'NAVIGATE'; }, diff --git a/example/TabNavigator.tsx b/example/TabNavigator.tsx index cbf0c8ad..cdbfd62b 100644 --- a/example/TabNavigator.tsx +++ b/example/TabNavigator.tsx @@ -151,6 +151,10 @@ const TabRouter: Router = { }; }, + shouldActionPropagateToChildren(action) { + return action.type === 'NAVIGATE'; + }, + shouldActionChangeFocus(action) { return action.type === 'NAVIGATE'; }, diff --git a/src/types.tsx b/src/types.tsx index 43707b3e..c67caf39 100644 --- a/src/types.tsx +++ b/src/types.tsx @@ -73,6 +73,12 @@ export type Router = { } ): NavigationState; + /** + * Whether the action bubbles to other navigators + * When an action isn't handled by current navigator, it can be passed to nested navigators + */ + shouldActionPropagateToChildren(action: Action): boolean; + /** * Whether the action should also change focus in parent navigator */ diff --git a/src/useNavigationBuilder.tsx b/src/useNavigationBuilder.tsx index a3b84216..b950fefe 100644 --- a/src/useNavigationBuilder.tsx +++ b/src/useNavigationBuilder.tsx @@ -19,7 +19,7 @@ type Options = { children: React.ReactNode; }; -type HandleAction = (action: NavigationAction, fromKey: string) => boolean; +type HandleAction = (action: NavigationAction, fromKey?: string) => boolean; const NavigationBuilderContext = React.createContext<{ helpers?: NavigationHelpers; @@ -134,19 +134,22 @@ export default function useNavigationBuilder( return true; } - // If router returned `null`, it didn't handle it - // try to delegate the action to child navigators - for (let i = dispatchListeners.current.length - 1; i >= 0; i--) { - const listener = dispatchListeners.current[i]; + if ( + fromKey === undefined && + router.shouldActionPropagateToChildren(action) + ) { + // Try to delegate the action to child navigators + for (let i = dispatchListeners.current.length - 1; i >= 0; i--) { + const listener = dispatchListeners.current[i]; - if (listener(action, state.key)) { - return true; + if (listener(action, state.key)) { + return true; + } } } if (handleActionParent !== undefined) { - // If non of the child navigators could handle the action, delegate it to parent - // This will enable sibling navigators to handle the action + // Bubble action to the parent if the current navigator didn't handle it if (handleActionParent(action, state.key)) { return true; }