React components library

React Native Web #

So far, I have created two libraries for presentational components, one for web and another one for mobile. How good would it be if we had a way to reuse those components for web and mobile? There is, react-native-web offers a way to solve this. I am going to explore it here with an isolated library for presentational components, used, later, by our spa and mobileapplication.

Go to packages folder:

´´´bash
npx tsdx create ui-shared
´´´

Choose react with storybook template.

Update /packages/ui-shared/package.json name:

"name": "@mr/ui-shared",

I Remove packages/ui-shared/examples project, since we will be using storybook to see our components working. Also, removed packages/ui-shared/test/blah.test.tsx. It was using some boilerplate code, we will not use.

Add External dependency for react-native-web, react-native and accordingly types. Here react-native-web will only be needed to visualize our components with storybook:

yarn lerna add react-native --scope=@mr/ui-shared --dev
yarn lerna add react-native-web --scope=@mr/ui-shared --dev
yarn lerna add @types/react-native --scope=@mr/ui-shared --dev

Lets create our simple BookCard component:

pacakges/ui-shared/src/components/BookCard/index.tsx

import React from 'react';
import { View, Text } from 'react-native';

export default function BookCard({ book }: { book: any }) {

  return (
    <View>
      <Text>{book.title}</Text>
      <Text>{book.author}</Text>
      <Text>{book.tag}</Text>
    </View>
  );
}

Again, I am using the book: any. I will fix it later, to use our own IBook type.

Update pacakges/ui-shared/src/index.tsx

import BookCard from './components/BookCard';

export { BookCard };

Storybook #

We want to be able to test and visualize our ui compoments idependently, without needing to have a full application. For That we use storybook:

Removed stories/Things.stories.tsx and created stories/BookCard.stories.tsx for our new component:

import React from 'react';
import { Meta, Story } from '@storybook/react';
import { BookCard } from '../src';

const meta: Meta = {
  title: 'BookCard',
  component: BookCard,
  argTypes: {
    book: {
      title: 'text',
      author: 'text',
      tag: 'text',
      defaultValue: {
        title: "Clean Code", author: 'Uncle Bob', tag: 'software'
      }
    },
  },
  parameters: {    
    controls: { expanded: true },
  },
};

export default meta;

const Template: Story = args => ;

// By passing using the Args format for exported stories, you can control the props for a component for reuse in a test
// https://storybook.js.org/docs/react/workflows/unit-testing
export const Default = Template.bind({});

Default.args = {}; 

And start storybook:

yarn storybook

It will fail because story book is trying to render react-native components on the web. It is here react-native-web enters. For storybook to use react-native-webin place of react-nativewe need to override some webpack configs that will make a link for react-native-web to be used in place of react-native when it is imported.

It is explained here.

I created a file packags/ui-shared/.storybook/webpack.config.js with:

module.exports = async ({ config }) => {
  config.resolve.alias = {
    'react-native$': 'react-native-web'
  };

  return config;
};

Now, execute yarn storybook again and it should work, starting a storybook website with a visualization of our BookCard component.

I also removied react-domdependencies, since it is not being used directly:

yarn workspace @mr/ui-shared remove react-dom @types/react-dom

Next, I will start using ui-shared library on packages/spaand packages/mobile, not needing ui-web and ui-mobile anymore.

Published