Create a ReactNative StorybookProvider
- typescript
- react-native
- storybook
There are different ways to integrate Storybook into your ReactNative application. You can either use different scripts that change the application entry point based on an environment/config variable or, more conveniently, you can add a menu item to the dev settings/menu that switches dynamically between your application and your Storybook setup. In this blog post, I will take the second approach and try to improve the solution a bit.
The problem I see with the proposed solution in the linked blog article is that you clutter up your App component quite a bit:
import React, { useState, useEffect, useCallback } from 'react';
import { addMenuItem } from 'react-native/Libraries/Utilities/DevSettings';
export const App = () => {
const [showStorybook, setShowStorybook] = useState(false);
const toggleStorybook = useCallback(
() => setShowStorybook((previousState) => !previousState),
[]
);
useEffect(() => {
if (__DEV__) {
addMenuItem("Toggle Storybook", toggleStorybook);
}
}, []);
if (__DEV__) {
const Storybook = require("../../.storybook/Storybook").default;
if (showStorybook) {
return <Storybook />;
}
}
return (
<SomeProvider>
<SomeOtherProvider>
<NavigationProvider />
</SomeOtherProvider>
</SomeProvider>
);
};
Wouldn’t it be nicer if your App
component would look like this:
import React from 'react';
export const App = () => {
return (
<StorybookProvider>
<SomeProvider>
<SomeOtherProvider>
<NavigationProvider />
</SomeOtherProvider>
</SomeProvider>
</StorybookProvider>
);
};
This is exactly what I did in this pull request. The StorybookProvider
then handles everything related to the dev settings/menu and the loading of Storybook:
import React, { useState, useEffect, useCallback } from 'react';
import { addMenuItem } from 'react-native/Libraries/Utilities/DevSettings';
export const StorybookProvider: StorybookProviderType = ({
children,
}: {
children: React.ReactNode;
}) => {
const [showStorybook, setShowStorybook] = useState(false);
const toggleStorybook = useCallback(
() => setShowStorybook(previousState => !previousState),
[],
);
useEffect(
() => {
if (__DEV__) {
addMenuItem('Toggle Storybook', toggleStorybook);
}
},
[],
);
if (__DEV__) {
const Storybook = require('../../.storybook/Storybook').default;
if (showStorybook) {
return <Storybook />;
}
}
return children;
};