Building React Components

Riverton Utah - Arial Drone Long Exposure

Component Workflow

  • Break down the design into components
  • Code the component in isolation
  • Publish
  • Consume
  • Re-use
  • Repeat

Component Workflow

  • Break down the design into components

Isolation

better reusability

StoryBook

React Storybook is a UI development environment for your React components. With it, you can visualize different states of your UI components and develop them interactively.

https://getstorybook.io/

https://github.com/kadirahq/react-storybook

webpack

https://webpack.github.io/

// webpack is a module bundler
// This means webpack takes modules with dependencies
//   and emits static assets representing those modules.
...
// "Loaders" can be used to preprocess files.

.

Help!

Component Workflow

  • Break down the design into components
  • Code the component in isolation

Create a component Project

cd ~/path/to/your/code
npm i -g ldsjs --registry http://icsnpm.ldschurch.org
ldsjs react-component tile
cd tile
atom .
git init
git add .
git commit -m 'initial commit'
npm i --cache-min 999999
npm i join-classnames --save
npm i normalize.css --save

./package.json

  • <scripts>
    • `npm run components` to start up StoryBook
    • You can also run your tests and linting
  • <main>
    • points at /scr/Component.js so this is the entry point into the code.
    • note: all source for the component is in ./src

./package.json

  • Modify the project name to have the '@lds' namespace
"name": "@lds/tile",

Fresh Start

Remove the contents of...

  • ./src/Component.js
  • ./src/Component.css
  • ./src/ComponentStory.js
  • ./src/ComponentSpec.js

And Delete...

  • ./src/Homer.png

Hello World

import styles from './Component.css';

export default () => (
    <section className={styles.container}>
        Hello World
    </section>
);

./src/Component.js

Yuck?

import styles from './Component.css';

export default () => (
    <section className={styles.container}>
        Hello World
    </section>
);

./src/Component.js

JSX not required

React.createElement("div",
    { className: styles.container },
    "Hello World"
);

...if you muscle your way past the gag reflex, all kinds of food possibilities open up.

Emile
Ratatouille

  • ES6 arrow function
  • className instead of class
import styles from './Component.css';

export default () => (
    <section className={styles.container}>
        Hello World
    </section>
);

./src/Component.js

  • htmlFor instead of for

Other Details

Tile StoryBook Story

import { storiesOf } from '@kadira/storybook';
import Tile from './Component';

storiesOf('Tile', module)
    .add('default', () => (
        <Tile />
    ));

./src/ComponentStory.js

run StoryBook

Props

import styles from './Component.css';
import classes from 'join-classnames';

export default ({
        title,
        subtitle,
        image, //object
        className
}) => (
    <section className={classes(className, styles.container)}>
        <img {...image} />
        <div>
            <h2>{title}</h2>
            <h3>{subtitle}</h3>
        </div>
    </section>
);

./src/Component.js

Send the props in the story

import { storiesOf } from '@kadira/storybook';
import Tile from './Component';
import abaNigeria from './aba-nigeria.jpg';

storiesOf('Tile', module)
    .add('default', () => (
        <Tile
            title="Aba Nigeria"
            subtitle="Nigeria, Aba, Abia State"
            image={{
                src: abaNigeria,
                alt: "Nigeria Temple"
            }}
        />
    ))

./src/ComponentStory.js

Styling

Image on the left

.container {
    display: flex;
}

./src/Component.css

normalize.css & fonts

@import 'normalize.css';
@import 'https://fonts.googleapis.com/css?family=Open+Sans:light,bold';

.container {
    display: flex;
    font-family: 'Open Sans', sans-serif;
    color: #53565a;
}

./src/Component.css

Style the title & subtitle

<h2 className={styles.title}>{title}</h2>
<h3 className={styles.subtitle}>{subtitle}</h3>

./src/Component.js

Position & size the title & subtitle

.title {
    margin: 0 0 .25rem .75rem;
    font-size: 1.125em;
    font-weight: 300;
}

.subtitle {
    margin: 0 0 0 .75rem;
    font-size: .625em;
    font-weight: 700;
    text-transform: uppercase;
}

./src/Component.css

More Stories!

  • Long title
  • Long subtitle
  • Long title and subtitle
  • Stack the tiles like in the design

Long title, subtitle, and both

    .add('long title', () => (
        <Tile
            title="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod"
            subtitle="Nigeria, Aba, Abia State"
            image={{ src: abaNigeria, alt: "Nigeria Temple"}}
        />
    ))
    .add('long subtitle', () => (
        <Tile
            title="Aba Nigeria"
            subtitle="Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo"
            image={{ src: abaNigeria, alt: "Nigeria Temple"}}
        />
    ))
    .add('long both', () => (
        <Tile
            title="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod"
            subtitle="Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo"
            image={{ src: abaNigeria, alt: "Nigeria Temple"}}
        />
    ))

./src/ComponentStory.js

Prevent Image Stretch

.container {
    display: flex;
    align-items: flex-start;
    font-family: 'Open Sans', sans-serif;
    color: #53565a;
}

./src/Component.css

Stacked Layout

A story that looks like the original layout is like a functional test.

It can help make sure that future changes don't break the original context.

.add('list', () => (
            <Tile
                title="Aba Nigeria"
                subtitle="Nigeria, Aba, Abia State"
                image={{src: abaNigeria, alt: "Nigeria Temple"}}
            />
            <Tile
                title="Accra Ghana"
                subtitle="Ghana, Ridge, Accra"
                image={{src: accraGhana, alt: "Ghana Temple"}}
            />
            <Tile
                title="Adelaide Australia"
                subtitle="Australia, Marden, South Australia"
                image={{src: adelaideAustralia, alt: "Australia Temple"}}
            />
            <Tile
                title="Albuquerque New Mexico"
                subtitle="United States, Albuquerque, New Mexico"
                image={{src: albuquerque, alt: "Albuquerque Temple"}}
            />
    ))

./src/ComponentStory.js

...
import accraGhana from './accra-ghana.jpg';
import adelaideAustralia from './adelaide-australia.jpg';
import albuquerque from './albuquerque-new-mexico.jpg';
...

add some space between

 

import styles from './ComponentStory.css';
...
.tile {
    margin-bottom: 1rem;
}

./src/ComponentStory.css

Component Workflow

  • Break down the design into components
  • Code the component in isolation
  • Publish

Publish

git commit...
git tag...
git push...
npm adduser...
npm publish

terminal

Bug: A Tile without an image leaves a stray <img> tag in the html

Illustrate the bug with a Story

.add('no image', () => (
    <Tile
        title="Aba Nigeria"
        subtitle="Nigeria, Aba, Abia State"
    />
))

./src/ComponentStory.js

Fix It

{image && <img {...image}/>}

./src/Component.js

Fix it Right

./src/Component.js

.image {
    margin-right: .75rem;
}
.title {
    margin: 0 0 .25rem 0;
    font-size: 1.125em;
    font-weight: 300;
}
.subtitle {
    margin: 0;
    font-size: .625em;
    font-weight: 700;
    text-transform: uppercase;
}
{image && <img {...image} className={styles.image}/>}

./src/Component.css

Re-Publish

npm version [<newversion> | major | minor | patch]
git commit...
git tag...
git push...
npm publish

terminal

Component Workflow

  • Break down the design into components
  • Code the component in isolation
  • Publish
  • Consume

Consume

import Tile from '@lds/tile';
...

        <Tile
            title="Aba Nigeria"
            subtitle="Nigeria, Aba, Abia State"
            image={{
                src: abaNigeria,
                alt: "Nigeria Temple"
            }}
            className={styles.tile}
        />

../projectb/src/components/OtherComponent.js

npm i @lds/tile --save

terminal

Component Workflow

  • Break down the design into components
  • Code the component in isolation
  • Publish
  • Consume
  • Re-use
  • Repeat

The End

San Juan, Puerto Rico

Building React Components

By Bruce Campbell

Building React Components

  • 928