I recently set up Storybook for a React Native/TypeScript project. It wasn't so different from using Storybook for web dev, but there were a few catches. I found their official tutorial to be outdated sometimes, and their Github README was up-to-date but didn't have all the information I wanted.
@storybook/react-native-server for using the web interface
react-native-storybook-loader for dynamic story loading
Lint: ESLint (Standard JS format)
CI: Github Actions
How to use
Clone this repo
yarn install
If you're using an iOS emulator, npx pod-install
Create an .env file
Copy the contents of .env.sample
yarn storybook to start the Storybook Server (localhost:7007)
yarn ios or yarn android to start Storybook in the emulator
NOTE: In order to boot up Storybook, it's necessary to set the environment variable LOAD_STORYBOOK to true (steps 4 and 5 above). Otherwise, it will boot up the default app created by React Native CLI.
Since you're reading this post, I'm going to assume you already have a project set up using the React Native CLI.
NOTE: I can't guarantee that the same steps will work for Expo projects.
Step 1: Install Storybook
Run the command below from your project root. This will install the necessary packages and add boilerplate code for you.
npx -p @storybook/cli sb init --type react_native
When it prompts you whether to install @storybook/react-native-server, hit yes.
Basically, the Storybook Server package lets you use the web interface for switching between components and manipulating knobs, instead of having to do everything from your emulator (it's the same UI as Storybook for other frameworks).
This is what it will look like with the web interface:
If you're developing for iOS, you should also run a pod install from the ios/ directory.
Step 2: Conditionally render Storybook
Now, let's add the enviroment variable LOAD_STORYBOOK, and use this flag to determine whether we should load your actual app or Storybook.
NOTE: This is one of the ways recommended in Storybook's README.
Add LOAD_STORYBOOK flag
There are a few ways to use environment variables in React Native, but I used react-native-config.
Setup is very simple:
yarn add react-native-config, then pod install
If you're developing for Android, add an import line as described here
In your project root, create an .env file
Any environment variables you add to .env can be accessed as Config.YOUR_ENVIRONMENT_VARIABLE
Now, add the environment variable LOAD_STORYBOOK=true to .env.
Render Storybook if LOAD_STORYBOOK=true
In App.tsx, change your code like below so that Storybook is rendered conditionally.
importStorybookUIfrom'./storybook'importConfigfrom'react-native-config'constApp=()=>{return (// Your actual app)}exportdefaultConfig.LOAD_STORYBOOK==='true'?StorybookUI:App
Step 3: Boot Storybook
There are a some other things to configure, but at this point, you should be able to boot Storybook and make sure it works.
First, boot Storybook Server (the web interface) with this command:
yarn storybook
When it's done booting, a browser window should open that looks like this (if not, you can just access localhost:7007):
At this point, the sidebar menu should show a loading animation.
Next, run yarn ios or yarn android. Since we set LOAD_STORYBOOK=true, this runs Storybook instead of your actual app.
Once it boots, the Storybook Server's sidebar should be populated with the stories you have, allowing you to navigate via the web UI (like the GIF from step 1).
Steps to take if Storybook Server doesn't work with the Android emulator
For Android, you may find that the sidebar doesn't get populated even when Storybook has booted in your emulator. There were some Github issues (like this one) discussing this phenomenon. The advice I found online was to run adb reverse tcp:7007 tcp:7007, but ultimately, what solved it for me was to specify the host parameter to be the Android localhost.
// storybook/index.jsconstStorybookUIRoot=getStorybookUI({// Add the line belowhost:Platform.OS==='android'?'10.0.2.2':'0.0.0.0'});
Step 4: Take care of asyncStorage warning
You'll probably see a warning in the metro server logs that looks like this:
WARN Starting Storybook v5.3.0, we require to manually pass an asyncStorage prop. Pass null to disable or use one from @react-native-community or react-native itself.
The benefit of using Async Storage is so that when users refresh the app, Storybook can open their last visited story.
Configuring this is simple; just pass it in as below.
NOTE: If you don't have the @react-native-community/async-storage package, you'll have to install it first.
// storybook/index.jsconstStorybookUIRoot=getStorybookUI({host:Platform.OS==='android'?'10.0.2.2':'0.0.0.0',// Add the line belowasyncStorage:require('@react-native-community/async-storage').default});
Step 5: Add Storybook Loader
React Native Storybook Loader is technically not necessary for using Storybook, but it's a convenient package that frees you from the task of having to write an import statement for every story file. Storybook Loader executes a script when you boot up Storybook, which auto-generates a file with the necessary import statemnents.
Now, all that's left is to add your own stories (and remove unnecessary boilerplate code). You don't have to add any packages or configuration for writing your stories in TypeScript; just use the .stories.tsx extension.
Here is an example:
If you plan to reuse CenterView, the boilerplate component that places your story code at the center of the emulator screen, you need to rewrite it in TypeScript or you will encounter some type errors. This is fairly straightforward - just rewrite it like so (the exact changes can be seen in this commit):