React Navigation 5 and Storybook

16 March 2022

StoryBook navigation object not found with React Native
Photo by jeremybishop

I am releasing a book about the React Native ecosystem, which covers everything I wish I had known before I started working with this technology.

If you appreciate my work and would like to show your support, please check the Road to React Native.

Designing at scale is not an easy task —especially on mobile. User flows rapidly become complex and it takes a ridiculous amount of time to test every single scenario.

As a React Native developer working freelance, I code on different stacks. Today I will cover the problem I faced when I wanted to connect these tools together:

Since 2017, I follow the "Component Driven Development" way of working. Like Lego bricks, all my components are loosely-coupled and independent. I assemble them to test behavior with Storybook. But if you want to have access to the navigation you will encounter this error: {navigation} object is not defined.

The Problem

If you’ve tried creating a story component that uses the useNavigation hook, you’ve likely seen this error message:

Couldn’t find a navigation object. Is your component inside a screen in a navigator?

This happens because the useNavigation hook needs to retrieve the navigation prop from a parent Screen component, and you’re most likely rendering the component in isolation. This leads to an error since the hook is not able to retrieve the navigation prop.

Couldn't find a navigation object.

Don’t panic. I found the solution.

Solution: Wrapping your Story component with a decorator

You could create a MockedNavigator component as described on this tread on GitHub.

// storybook/StoryNavigator.tsx

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
// import { createNativeStackNavigator } from "@react-navigation/native-stack";

/**
* Helper component tor create a Dummy Stack to access {navigation} object on *.story.tsx files
*
* @usage add this decorator
* ```
* .addDecorator(NavigationDecorator)
* ```
*/

const StoryBookStack = createStackNavigator();
// or the native one
// const StoryBookStack = createNativeStackNavigator();

export const NavigationDecorator = (story) => {
const Screen = () => story();
return (
<NavigationContainer independent={true}>
<StoryBookStack.Navigator>
<StoryBookStack.Screen
name="MyStorybookScreen"
component={Screen}
options={{header: () => null}}
/>
</StoryBookStack.Navigator>
</NavigationContainer>
);
};

and then you can addDecorator

import {NavigationDecorator} from '~/storybook';

storiesOf('ScrollTabBar', module)
.addDecorator((fn) => <StoryScreen>{fn()}</StoryScreen>)
.addDecorator(NavigationDecorator)
.add('Style Presets', () => (
<Story>
<UseCase text="ScrollViewWithTabBar" usage="children">
<ScrollViewWithTabBar>
<DummyContent />
</ScrollViewWithTabBar>

The benefit of this approach is that it provides an actual navigation prop to the component.

Gravatar for dleuliette@gmail.com

Hi, I’m David, a french freelance developer working remotely. I’m the author of this blog, nice to meet you!

Subscribe?

Be the first to receive insightful articles and actionable resources that help you to elevate your skills.