Setting up Storybook for React Native/TypeScript (server, loader, iOS, Android)

Risa Fujii - Jan 10 '21 - - Dev Community

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.

This is a step-by-step walkthrough of how to set up Storybook for React Native, complete with the the web UI (@storybook/react-native-server), dynamic story loading (react-native-storybook-loader), and TypeScript.

Finished repo:

GitHub logo risafj / StorybookExampleReactNativeTS

Example repo for setting up Storybook for a React Native/TypeScript project.

Storybook Example React Native TypeScript

This repo showcases some components that I made for a personal React Native project (contained in a separate private repo).

I wrote a blog post about the Storybook setup process here:

https://dev.to/risafj/setting-up-storybook-for-react-native-typescript-server-loader-ios-android-3b0i

Technical stack

  • React Native
  • TypeScript
  • Storybook
    • @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

  1. Clone this repo
  2. yarn install
  3. If you're using an iOS emulator, npx pod-install
  4. Create an .env file
  5. Copy the contents of .env.sample
  6. yarn storybook to start the Storybook Server (localhost:7007)
  7. 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.




Prerequisites

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
Enter fullscreen mode Exit fullscreen mode

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:

storybook-server-gif

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:

  1. yarn add react-native-config, then pod install
  2. If you're developing for Android, add an import line as described here
  3. In your project root, create an .env file
  4. 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.

import StorybookUI from './storybook'
import Config from 'react-native-config'

const App = () => {
  return (
    // Your actual app
  )
}

export default Config.LOAD_STORYBOOK === 'true' ? StorybookUI : App
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

When it's done booting, a browser window should open that looks like this (if not, you can just access localhost:7007):

empty-storybook-server

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.js

const StorybookUIRoot = getStorybookUI({
  // Add the line below
  host: Platform.OS === 'android' ? '10.0.2.2' : '0.0.0.0'
});
Enter fullscreen mode Exit fullscreen mode

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.

According to the docs:

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.js

const StorybookUIRoot = getStorybookUI({
  host: Platform.OS === 'android' ? '10.0.2.2' : '0.0.0.0',
  // Add the line below
  asyncStorage: require('@react-native-community/async-storage').default
});
Enter fullscreen mode Exit fullscreen mode

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.

Their official README's quick start section covers everything you need, so I will link it here: https://github.com/elderfo/react-native-storybook-loader#quick-start

Step 6: Write your own stories (in TypeScript!)

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:

// src/components/atoms/CustomButton.stories.tsx

import { storiesOf } from '@storybook/react-native'
import { CenterView } from '../../../storybook/stories/CenterView'
import React from 'react'
import { CustomButton } from './CustomButton'

storiesOf('Atoms/CustomButton', module)
  .addDecorator((getStory) => <CenterView>{ getStory() }</CenterView>)
  .add('confirm', () => (
    <CustomButton text="Confirm" colorModifier="confirm" />
  ))
Enter fullscreen mode Exit fullscreen mode

Caveat

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):

// storybook/stories/CenterView/index.tsx

import React from 'react'
import { StyleSheet, View } from 'react-native'

interface Props {
  children: any
}

export const CenterView = (props: Props) => {
  return (
    <View style={ styles.main }>
      { props.children }
    </View>
  )
}

const styles = StyleSheet.create({
  main: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  }
})
Enter fullscreen mode Exit fullscreen mode

Thank you for reading!


Credits:
Many thanks to @rob117, who helped with the solution to the compatibility issue between the Storybook Server and Android emulator.

. . . . . . . . . . . . . . . .
Terabox Video Player