I gave this talk at Squares Conference 2016.
http://squaresconference.com
Code demo from the talk…
http://t7.github.io/react-starter
https://github.com/t7/react-starter
3. • Father of two rambunctious boys, who
are big fans of Star Wars and Legos.
• Self-taught. That just means I pestered
lots of people until I learned how to do
this stuff. Yet, I still doubt myself daily.
• I build the "legacy" software of tomorrow.
• I generally have a "get off my lawn"
attitude towards emerging technology.
Nathan Smith
Principal Front-End
Architect
Introduction
6. Perhaps unsurprisingly, my off
the cuff, ill-informed reaction…
ended up being totally wrong.
(But, admitting when you're wrong
is part of being a grown-up, right?)
8. Today, I would like to talk
to you about the "three Rs."
•Reading
•wRiting
•aRithmetic
9. There are three fundamental
aspects of most React apps.
•React = the "V" (and "C") layer.
•Redux = the "M" layer.
•Router = um, the "URL" layer? :)
10. PROOF POSITIVE OF COOL PROJECTS? LOGOS!
github.com/reactjs/react-routergithub.com/reactjs/reduxgithub.com/facebook/react
11. Actually, my projects are more like this.
Accounting.js Babel ECMAScript 6+ ESLint
Jest Lodash Markdown Moment.js
NPM PostCSS React ReactDOM
React Router React Test Utils Redux Sass (SCSS)
Sass-Lint Standard Webpack window.fetch
15. NOTE:
First off, let me say that what I am showing
you today is simply "a" way to do React.
It is not necessarily "the" (right, only) way.
This is simply the approach we have settled
on, after trial and error with various projects.
16. One thing to keep in mind when working
with React is the oft-repeated phrase…
"Everything is a component."
A component is essentially anything
that looks like this: <UppercaseTag>
(Components may contain other components.)
17. Any time you see something like this…
<UppercaseTag />
<UppercaseTag> content </UppercaseTag>
…that is usually a React "class," which may or may
not be an actual JavaScript (ECMAScript 6) class.
For the purpose of this talk, let's assume they all are.
18. NOTE:
Syntax that looks like HTML but is
embedded (not simply within a string)
in JavaScript is referred to as "JSX."
It is an artificial construct that means:
React.createElement(UppercaseTag, …)
19.
20.
21. Conceptually, all React apps are structured like this.
– great-grandparent
–– grandparent
––– parent
–––– child
–––– child
–– grandparent
––– parent
–––– child
–––– child
22. Components talk to each other via "props."
<UppercaseTag foo='bar' />
^ Here, the parent of <UppercaseTag> is passing
down a prop called foo, with the value of 'bar'.
Within the UppercaseTag class, that is usable via…
this.props.foo // "bar"
23. Typically, in order for a child to talk to a parent, the parent
component passes a callback function prop to the child.
Here's an example of how we use our <Input /> component.
<Input
handleChange={
function (e, value) {
// `e` is the event.
// `value` is the *.value of the input.
}
}
/>
24. Q: What if the parent does not "care" about the grandparent or the
child, other than the fact that they are nested within one another?
– grandparent <—> "parent" props
–– parent <—> "grandparent" and "child" props
––– child <—> "parent" props
25. A: That is why Redux was created, to allow each component to
get and/or set changes to a shared object store, aka "app state."
– grandparent <—> Redux
–– parent
––– child <—> Redux
^ If the parent has no inherent reason to care about the shared
state, it need not be involved as an unnecessary middleman.
26. NOTE: Dan Abramov is
on the React team, and is
the creator of Redux.
27. NOTE: Ryan Florence is
one of the creators of
React Router. He does
not usually use Redux.
28. You may sometimes hear about local state as being confined to each
individual React component. That is correct. Components can have...
this.state.batmanIdentity // "Bruce Wayne"
this.state.checked // boolean
this.state.hasPlaceholder // boolean
this.state.value // string
…data that is internal. That self-contained state can be shared with child
components via props, and can be passed to parents via callback functions.
Redux "app state" makes things like this.props.foo available to multiple
components, from a source other than their parents. Redux is a "parent to all."
30. Angular apps usually
have "decorated" HTML,
with <tag ng-foo="…">
attributes sprinkled
throughout. HTML loads,
JS parses it, and then
applies functionality.
31. React apps usually have
a very minimal HTML
page, with a single
insertion point, such as
<div id="app"> and then
the rest of the markup is
generated entirely by JS.
32. Having full knowledge of the generated HTML, React is
able to keep track of the "virtual DOM" and do precise
updates accordingly. This means you rarely, if ever,
actually make any of your HTML changes directly.
No more typing… $('#foo').addClass('bar')
33. Anatomy of a React Component
NOTE:
This is an contrived example. You
would not normally use internal
state, when something is just
directly set via props anyway.
However, this illustrates the
relationship between state and
props. State is internal, whereas
props come from a component
that resides a "level above."
34. Anatomy of a React Component
NOTE:
Most of the time, you can safely
leave out the constructor. It is
called implicitly, if absent.
This example also shows how
you might use defaultProps, to
provide a fallback placeholder for
this.props.name. This is handy
when awaiting an Ajax request.
41. How I feel about neatly nested nested React components.
bestpysanky.com/9-pcs-10-Semenov-Russian-Nesting-Dolls-p/nds09000.htm
42. This index.js file kicks off
the entire app. It pulls in
<Provider> as the first
component, which wraps
{routes} and makes
shared Redux "app
state" available.
43. In routes.js we have the
pattern matching of
various paths, and their
respective components.
We are also setting a
title prop that will be
added to the <title> tag
via a Page component.
44. This a simple <Page>
level component. In this
case, it is the fallback for
when a route is not
found. We are pulling in a
Markdown file, with a
basic "404" message.
It utilizes the <App>
layout component,
wrapping the content.
45. This is an example of the
<App> layout component,
which pulls in app level
header, main, footer, etc.
{this.props.children}
is the Markdown content,
passed forward from the
<Page> component.
46. This is the <AppHeader>
component, which was
being used from within
the <App> component. It
contains the logo, and a
few links in a list.
It is making use of the
"Unsemantic" grid, via
<Grid> components.
47. Here, the <AppMain>
component is basically
just a pass-through for
content, simply wrapping
it in <main role="main">
for accessibility and
styling purposes.
49. Accessibility is best when done with advanced planning. For the
components we build, we make sure it is not just an afterthought.
50. This is actually an example of
the <AccordionMulti>
component, a not mutually
exclusive version of the
<Accordion> component.
51. First, the initial selected
state is set, based on
props passed in from the
parent component.
If it does not exist, then
the accordion starts out
completely collapsed.
We also ensure a unique
id, to map ARIA roles to
various elements.
52. In the event that the parent
component wants to override
the internal state, we have
componentWillReceiveProps
which will potentially cause a
state change by calling…
this.setState({key:val})
53. The handleClick method
is called internally when
an accordion header is
clicked. This sets the
component state, and if a
this.props.handleClick
callback exists from the
parent, it will call it too.
54. Here, an otherwise
tedious process is made
fully automatic. That is,
obviating the manual
assignment of a unique
id to each header and
panel, in order to ensure
ARIA accessibility hooks
are properly associated
to their peer elements.
55. In the render method, ARIA
roles are set, based on the
internal component state.
For each section of accordion
content, a child component
<AccordionHeader> is created.
Also note, an accordion is
technically a role="tablist"
57. <Page> is like Tony Stark. Redux connect adds the "suit" to this.props
This is done through a process called "currying," when a function returns another, modified function.
58. First, we need to import
bindActionCreators and
connect from redux, and
react-redux. These will
allow us to make external
functions usable within
the <Page> component.
59. Next, we import our own
"actions" from the
various files we have
stored in the directory
"/source/redux/actions".
This directory is not to
be confused with NPM's
"/node_modules/redux".
60. At the end of the file, we
have Page.propTypes
validation, so that React
can warn us if the wrong
type of props are passed.
string vs. boolean, etc.
63. Lastly, connect uses
"currying" to make these
changes innate to <Page>.
You could think of <Page> as
Tony Stark, and the result of
the connect call as wrapping
him in an Iron Man suit.
<Page> then has all the
additional props and functions
applied to it from Redux.
64. Thanks to the aforementioned
currying of connect, we now
have multiple "action"
methods available from
Redux, that can be called from
within our <Page> component.
65. When we actually make use of
<AccordionMulti> we pass in
the selectedFaqAccordion
"app state," and the callback
handleClickFaqAccordion
which triggers our Redux
"action" state change.
67. The way Redux layers
together various state
changes into one object
reminds me of the SNL skit
"Taco Town" where they
wrap a hard-shell taco in a
soft-shell taco, in a crepe,
in a pizza, in a pancake,
that is deep fried…
68.
69. In "/source/redux/index.js" we
have what is referred to as a
rootReducer, which
aggregates the various child
reducers. A common mistake
is to forget to add a new
reducer here. That can lead to
frustration when debugging.
70. In "/source/redux/_types.js"
there is a list of action types,
which have been assigned to
constants. While this may
seem silly, because they are
just strings, it enforces unique
action names. This is helpful
as your project grows larger.
71. Each reducer reads from the
aforementioned _types.js file,
and potentially pivots based
on what type of action it is.
In this case, we are saving
changes to the selected state
of the accordion. Notice that
the state is being get/set by
utils.storage, which allows
the state change to persist
across page loads, saved in
window.localStorage
72. This file makes the function
this.props.updateFaqAccordion
available to any component
where connect is used on it.
It passes forward any changes to
the accordion's selected state.
76. By default, Jest wants to be
helpful and "mock" every file you
include. But, we can just disable
that, as we know exactly what we
want to test. It speeds things up.
77. We give our test suite a name,
the same as our <UppercaseTag>.
Then, we render it into the
testing concept of a "document,"
and assign a parent reference.
Then we can use vanilla DOM
methods: querySelectorAll, etc.
78. For each aspect we want to test,
we pass a string and function to
"it" — made available by Jest.
it('does something', …)
Each resulting pass/fail is shown
in the command line, via…
npm run test
80. In the "/source/utils/index.js" file,
we import various utility
methods, and bundle them under
a single object, named utils.
81. In the "/source/utils/_ajax.js" file,
we have a wrapper around
window.fetch — which is the
new HTML5 replacement for the
quirkiness of XMLHttpRequest.
You can specify a host, url,
method, params — sent as query
or body based on method — and
callbacks for success/error.
This file is not presently used in
the React starter project, but we
do make use of it in real projects
that require us to do Ajax.
82. I use this utils.save method
quite a bit, when I need to view
an API response that is too
cumbersome to read as JSON in
the browser's developer tools.
Instead, it causes the browser to
download a nicely formatted
*.json file, so I can scroll through
it using a text editor instead.
83. Clicking the Save JSON
button on the "/#/profile"
page of the demo app will
download a JSON file…
form_data.json
In it, you will see the
current state of the form
fields and their values.