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
Example: airbnb date picker
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
- `npm run components`
- http://localhost:9999
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
- 944