React Training
LDS Stack Team
http://slides.com/tuxsudo/react-training
System Check
Please try to run these commands from the CLI
node --version # >=8.x.x
npm --version # >= 5.2.x
ldsjs --version # >= 1.1.3
Create a Project
ldsjs react bootcamp-labs
Grab the Labs
Modern JavaScript
Part 1
ES Modules
Modern JavaScript
The Past
due to a lack of a module system in Javascript, two competing workarounds had been developed: CommonJS (node), and AMD (RequireJS).
The following is an example of a CommonJs module, which is commonly found in Node.js on the server, and Browserify on the client.
// lib.js (the export)
module.exports = {
lib: () => { ... }
};
// file.js (the import)
var lib = require('./lib.js');
ES Modules
An ES6 module is a file containing JS code. There’s no special module keyword; a module mostly reads just like a script. There are two differences.
ES6 modules are automatically strict-mode code, even if you don’t write "use strict"; in them.
You can use import and export in modules.
ES Modules
An ES6 module is a file containing JS code. There’s no special module keyword; a module mostly reads just like a script.
// lib.js (the exporter)
export default () => {}
export const mySpecificFunction = () => {}
// file.js (the importer)
import lib from './lib.js';
import { mySpecificFunction } from './lib.js';
import lib, { mySpecificFunction } from './lib.js';
import lib, { mySpecificFunction, myOtherFunction } from './lib.js';
import * as everything from './lib.js';
import lib, * as everything from './lib.js';
import { mySpecificFunction as msf } from './lib.js';
ES Modules
modules can both import and export
import dep from "./my-deps";
export default () => {}
export const mySpecificFunction = () => {}
ES Modules
Everything declared inside a module is local to the module, by default. If you want something declared in a module to be public, so that other modules can use it, you must export that feature.
// file.js
// only in this module's scope
const mySecretVariable = "hello";
export const mySpecificFunction = () => {}
ES Modules
Import statements must be first (at the top of a file)
Resources
Arrow Functions
Modern JavaScript
Arrow Functions
- An arrow function expression has a shorter syntax compared to function expressions and does not bind its own this, arguments, super, or new.target.
- Arrow functions are always anonymous.
- These function expressions are best suited for non-method functions* and they can not be used as constructors.
//square function
function square(a) {
return a * a
}
//square function expression
const square = function(a) {
return a * a;
}
//A function expression using arrow syntax
const square = (a) => {
return a * a;
};
//Implicit Return
const square = (a) => a * a;
//no parameter parenthesis
const square = a => a * a;
Functions in JavaScript
The following functions are all equivalent. They accept a number, and return the square of that number.
param => true;
param => {return true};
(param1, param2) => (param1 + param2);
() => null;
() => { return true; }
() => (true)
() => ({ a: 1, b: 2 })
It will be helpful to be able to recognize different variations of function signatures by sight, and see that they all fall into the same pattern:
Recognize the Pattern
Some Helpful Conventions
If you are new to this syntax, consider always wrapping the parameters in parenthesis, and using a function body with an explicit return. This verbose style will work everywhere
const square = (a) => {
return a * a;
}
[].map((elem) => {
return {
a: elem.a,
b: elem.deep.b
}
});
Which Should I Use?
The recommendation is to use the appropriate syntax for the situation.
// scales verbosely
[].map((x, y) => {
return x * y;
});
// scales nicely
[].map( (x, y) => x * y);
arrow-functions
lab
Resources
Array Methods
Modern JavaScript
Array Methods
- map
- filter
- reduce
map
items.map( x => x * x )
The map() method creates a new array with the results of calling a provided function on every element
The new array will be the same size as the original array
map
items.map( x => x * x )
Accepts a Lambda Fuction which...
- 1st argument is the current array item
- Return value is added to the new array
optional arguments 2 and 3 are less commonly used
map examples
[0, 1, 2, 3, 4, 5, 6, 7]
.map((x) => 2**x)
// [1, 2, 4, 8, 16, 32, 64, 128]
[
{w:10, h:20, d:10},
{w:3, h:2, d:20},
{w:4, h:1, d:400},
{w:9000, h:3999, d:9191}
].map( ({w, h, d}) => w * h * d)
// [2000, 120, 1600, 330793281000]
items.filter((x) => x%2===0)
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
The new array will be the same size or smaller
filter
filter
Accepts a Lambda Fuction which...
- 1st argument is the current array item
-
Return determines if the item stays:
truthy=included, falsey=excluded
optional arguments 2 and 3 are less commonly used
items.filter( x => x%2===0 )
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
.filter((x) => x%2 ===0 );
[
"bacon cheeseburger",
"chicken sandwich",
"hamburger",
"bacon salad"
].filter((x) => /bacon/i.test(x) );
filter examples
items.reduce((acc, cur) => acc + cur, 0)
Applies a function against an accumulator and each element in the array to reduce it to a single value
Always results in a single item
reduce
lambda function accepts optional arguments 3 and 4, but they're less common
- 1st argument of lambda is the accumulation of values that will eventually be the final results (required)
- 2nd argument of the lambda is the current item as the array is iterated through
- Return value becomes the accumulation in the next iteration and then the final result
Accepts an initial accumulation value
items.reduce((acc, cur) => acc + cur, 0)
reduce
Accepts a Lambda Fuction which...
1
3
2
5
6
8
0
1
4
6
11
17
25
[1, 3, 2, 5, 6, 8].reduce(
(acc, cur) => acc + cur,
0
);
array-methods
lab
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
- https://atendesigngroup.com/blog/array-map-filter-and-reduce-js
Resources
Template Literals
Modern JavaScript
Template Literals
Template literals are string literals allowing embedded expressions. You can use multi-line strings and string interpolation features with them. They were called "template strings" in prior editions of the ES2015 / ES6 specification.
const price = 24.99;
const payments = 3;
const salesPitch = `Only ${payments} easy payments of $${price}!`
Note that the template literal is surrounded with back-ticks, not single quotes.
template-literals
lab
Resources
Default Parameters
Modern JavaScript
Default Parameters
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
/*
A function "add" with default
parameters which are used
if no values are passed
*/
const add = (a=1, b=2) => {
return a + b;
}
// call add with both parameters
console.log( add(3, 3) );
//call add with 1 missing parameter
console.log( add(3) );
//call add with no parameters
console.log( add() );
//call with one undefined parameter
console.log( add(undefined, 5) );
default-parameters
lab
Destructuring Assignment
Modern JavaScript
Destructuring Assignment
The destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects into distinct variables.
const BigBird = { height: `8'2"`, color: '#f7f16d', age: 'timeless' };
const { color, height } = BigBird;
//color === '#f7f16d'
//height === `8'2"`
const colors = [ '#f00', '#0f0', '#00f' ];
const [ red, green ] = colors;
//red === '#f00'
//green === '#0f0'
const [,, blue] = colors;
//blue === '#00f'
"color", "height", "red", "green" and "blue" would all be variables and could be used just like if you declared
"const color = "#f7f16d;"
Destructuring Assignment in Parameters
Values from an object can be destructured when that object is passed into a function as a parameter.
const render = ({title, description}) => {
console.log(title); // "..."
}
const bigObject = {
...
title: '...',
...
description: '...'
...
}
render(bigObject)
destructuring
lab
Resources
Spread & Rest
Modern JavaScript
Array & Object Spread
The spread syntax allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.
const a = [ 1, 2, 3 ]
const flatArray = [ ...a, 4, 5 ];
//flatArray == [ 1, 2, 3, 4, 5 ]
const b = { a: 1, b: 2, c: 10, d: { a: 1 } };
const flatObject = { ...b, c: 3 };
//flatObject == { a: 1, b: 2, c: 3, d: { a:1 } };
Array & Object Rest
When used in a destructuring assignment, the rest operator assigns the remaining (the rest of) values to a variable.
const numbers = [ 1, 2, 3, 4, 5 ];
const [ one, two, ...threeFourFive ] = numbers;
// threeFourFive === [ 3, 4, 5 ];
const data = { a: 1, b: 2, c: 4, d: 5 };
const { a, b, ...rest } = data;
// rest == { c: 4, d: 5 }
Explain This?
(({ a, b, z = 100, ...others }) => {
// a==1
// b==2
// z==100
// others = { c: 3, d: 4, e: 5}
})({ a: 1, b: 2, c: 3, d: 4, e: 5 })
spread-rest
lab
Resources
Promises
Modern JavaScript
Promises
- The Promise object is used for asynchronous computations.
- A Promise represents a value which may be available now, or in the future, or never.
- This is represented by three states: resolved, pending, or rejected.
Promises
// mock functions
const displayHoorayMessage = ()=>{};
const queueWelcomeEmail = ()=>{};
const queueHandwrittenPostcard = ()=>{};
const doError = ()=>{};
// a function that returns a promise
signUpNewUser()
.then( displayHoorayMessage )
.then( queueWelcomeEmail )
.catch( doError )
.then( queueHandwrittenPostcard )
.catch( doError );
- a resolved promise triggers the `.then` method
- a rejected promise triggers the `.catch` method
- the return value from `.then` and `.catch` is always a Promise
- the return value from .then and .catch will be the function input of the next triggered .then or .catchinput argument of the next `.then` or .catch
Promise.all
var p1 = new Promise( ( resolve, reject ) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise( ( resolve, reject ) => {
setTimeout(resolve, 2000, 2);
});
var p3 = new Promise( ( resolve, reject ) => {
setTimeout(resolve, 3000, 'three');
});
Promise.all([ p1, p2, p3 ]).then( values => {
console.log(values); // ["one", 2, "three"]
});
Promise.all returns a promise that resolves when all of the promises in the iterable argument have resolved, or rejects with the reason of the first failed promise.
Promise.resolve / Promise.reject
const results1 = Promise.resolve({ errors: false });
const results2 = Promise.reject({ errors: true });
any value can easily be converted into a promise
Async/Await
Async code that looks like synchronous code
// A bunch of functions
const displayHoorayMessage = () => {};
const queueWelcomeEmail = () => {};
const queueHandwrittenPostcard = () => {};
const doError = () => {};
(async () => {
try {
const data1 = await signUpNewUser();
const data2 = await queueWelcomeEmail(data1);
return queueHandwrittenPostcard(data2);
} catch (err) {
doError(err);
}
})();
promises
lab
Resources
Fetch
Modern JavaScript
Fetch
- The Fetch API provides a JavaScript interface for accessing and manipulating parts of the HTTP pipeline, such as requests and responses.
- It also provides a global fetch() method that provides an easy, logical way to fetch resources asynchronously across the network.
- Fetch returns a promise. Results or errors are accessed using "then" and "catch."
fetch('http://service.example.org/json')
.then(handleResponse)
.catch(handleError)
Fetch
A configuration object can be optionally passed into the `fetch` call. This allows headers, and other options to be set on the request.
fetch('http://service.example.org/json', {
method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default'
})
headers & configuration
Fetch
- Fetch returns a promise, and can be interacted with in the same way a promise is: using `then` and `catch`.
- In addition to the response body, the response object contains several helper functions and properties, such as ".json()" (converts response body to json), and ".ok" (checks the response status code)
fetch('http://service.example.org/json')
.then(res => res.ok? res.json() : Promise.reject(res))
.then(res => {
//do something with the response
})
.catch(err => {
//do something with the error
});
working with the respone
Fetch
fetch('http://service.example.org/json')
.then(res => res.ok ? res.json() : Promise.reject())
.then(({prop1, prop2}) => ({ prop1, prop2 }))
.then(res => {
//do stuff
})
.catch(res => console.log(res));
trimming a response
fetch
lab
Resources
Classes
Modern JavaScript
"Classes"
- JavaScript classes are "syntactical sugar" over JavaScript's existing prototype-based inheritance.
- The class syntax is not introducing a new classical-inheritance model to JavaScript.
- JavaScript classes provide a simpler syntax to create objects and deal with inheritance.
"Classes"
class Shape {
constructor(center) {
this.center = center;
}
}
const myShape = new Shape({ x: 0, y: 0 });
Extends
class Circle extends Shape {
constructor(radius, center) {
super(center);
this.radius = radius;
}
area() {
return Math.PI * (this.radius * this.radius);
}
}
const myCircle = new Circle( 15, { x: 0, y: 0 });
myCircle.area(); // 706.8583470577034
Classes extend other classes, using prototypal inheritance. If a child class contains a constructor, it must also call the parent constructor, using the "super" function.
Class "Fields"
// before
class Shape {
constructor() {
this.name = "Shape";
this.color = "Blue";
}
}
An extension to JS classes (stage3) allows for instance properties
// after
class Shape {
name = "Shape";
color = "Blue";
}
classes
lab
Resources
The Future
Modern JavaScript
ReactJS
Part 2
What is React?
ReactJS
JS Library UI Library
- web
- native
- vr
Declarative
- views reflect data
- easily account for different states
- more predictable code
- easier to debug
Component Based
- encapsulated components
- compose to build complex UIs
- components manage own state*
Virtual DOM
- fast
- declarative
- future friendly
Many Ways to React
- page widgets
- browser-only SPA
- server-only rendered templating
- universal/isomorphic apps
- react-react stack
- react-redux stack
- react-_________ stack
Good Sized
react
react-dom
Thinking in Components
ReactJS
Separation of Concerns
JS
CSS
HTML
JS
CSS
HTML
in a page model
/page-1
/page-2
what does it look like when we want to share & reuse smaller "page" components across multiple pages, apps & sites?
Separation of Concerns
JS
CSS
HTML
in a component model
Button, DatePicker, Modal, List, List-Item, Media
Button, DatePicker, Modal, List, List-Item, Media
Button, DatePicker, Modal, List, List-Item, Media
Separation of Concerns
JS
CSS
HTML
in a component model
Button
DatePicker
Modal
List
ListItem
Media
in this model, how a components fulfills its defined responsibility is an encapsulated, implementation detail
Best Practices: Redefined
Components IRL
Components IRL
Component driven design and development
- Facilitates reusability within an application & between applications
- Simplifies the mental model for developers when working on an isolated component → less errors
Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
💯
What are Components?
reusable markup & style
is a component
Tile
<Tile
title=""
subTitle=""
backgroundImageSrc=""
href=""
/>
AsideSection
are components
reusable markup & style
Split
Layout
also a component
<Split ratio="1/3" gapSize="xs">
<aside>I'm a distraction</aside>
<main>I'm the main content</main>
</Split>
reusable behaviors
are components
<Network
render={({ online }) =>
<p>You are online: {online ? 'Yep' : 'Nope'}.</p>
}
/>
Information
as components
<Fetch
url={url}
onData={handleData}
onError={handleError}
/>
Units of Work
are components
"good components" do one thing, do it well, are reusable, and are composable
Best Practice
JSX
ReactJS
JSX
const name = "Tacos";
const when = "always";
const thingToRender = (
<section>
<p>What should we eat: {name}</p>
<p>When should we them: {when}</p>
</section>
);
- open specification
- XML-like syntax extension to JS
- syntactic sugar that turns "tokens" into JS spec in a pre-processing stage
- although parts of JSX may look like HTML, it is not.
- in React, JSX turns into React.createElement
JSX
- camelCase "props"
-
class➡️ className -
for➡️ htmlFor - key when looping
- defaultValue
- always close tags
- JS expressions
camelCase Props
<input onChange={console.log} />
<div className="hello">hi</div>
class ➡️ className
<label htmlFor="otherId">hi</label>
for ➡️ htmlFor
<ul>
{[0, 1, 2].map( num =>
<li key={num}>{num}</li>
)}
</ul>
`key` (when looping)
<input defaultValue="hello" />
defaultValue
<input />
<br />
<hr />
<meta />
must close tags
<div>
{ Math.random() > 0.5 && <span>you win</span> }
</div>
<div>{ functionThatReturnsRenderable() }</div>
{ 5 > 3
? <strong>yes</strong>
: <small>no</small>
}
{values.map(n => <strong>{n}</strong>)}
<date>
{(new Date()).toLocaleString()}
</date>
Expressions
jsx
lab
- https://facebook.github.io/jsx/
Resources
Components
ReactJS
A function which returns JSX is called a component. Component names must be capitalized.
//Create Component
const MyComponent = () => (
<h1>A nice static component!</h1>
);
//Render the component
ReactDOM.render(
<MyComponent />,
document.getElementById("app")
);
A component could also include a function body
//Create Component
const MyComponent = () => {
// do stuff before returning JSX element
return (
<h1>A nice static component!</h1>
)
};
//Render the component
ReactDOM.render(
<MyComponent />,
document.getElementById("app")
);
- The simplest way to create a component is to write a function (as you've already seen)
- Generically, a function accepts inputs and produces output.
- For a React component, we call those inputs "props".
//Create Component
const Greet = (props) => (
<h1>Hello, {props.name}!</h1>
);
- Typically, props are descructured for clarity and simplicity
//Create Component
const Greet = ({ name }) => (
<h1>Hello, {name}!</h1>
);
Props can be:
strings
//Render the component
ReactDOM.render(
<Greet name="Alice" />,
document.getElementById("app")
);
Props can be:
integers
//Render the component
ReactDOM.render(
<Greet age={42} />,
document.getElementById("app")
);
Props can be:
objects
//Render the component
ReactDOM.render(
<Greet data={{ name: "Alice", gender: "Female"}} />
document.getElementById("app")
);
Props can be:
function reference
const callback = () => { console.log('Hello World') };
//Render the component
ReactDOM.render(
<Greet onClick={callback} />,
document.getElementById("app")
);
Props can be:
arrays
const people = ["Albert", "Scott"];
//Render the component
ReactDOM.render(
<Greet items={people} />,
document.getElementById("app")
);
Props can also be spread:
const person = {name: "Alice", gender: "Female"};
//Render the component
ReactDOM.render(
<Greet { ...person } />,
document.getElementById("app")
);
Props can be:
🎇 You Name It! 🎇
as long as it's an expression
component
lab
Resources
Styling
ReactJS
Styling in React
- Inline Styles
- Global CSS
- Import CSS
- CSS Modules
- CSS-in-JS
Styling in React
Inline Styles
Inline Styles use object literal notation in JSX
//Declare properties using camelCase
const myHeaderStyle = {
paddingTop:'1em',
fontFamily:'Palatino',
backgroundColor:'aliceblue'
};
const MyHeader=()=>(
<h3 style={myHeaderStyle}>
Styling in React
</h3>
);
Inline Styles
Pros
- No support for pseudo selectors (e.g. :hover, :visited, ext)
- No support for Media queries
- No support for animation
- No single style source, difficult to maintain at scale
- Styles scoped to component
- Not dependent on global styles
- 100% Reusable
- Dynamic Values
Cons
Inline Styles
Styling in React
Global CSS
Don't do this (generally)
Using Global CSS
Due to 'class' being a reserved word, you need to use 'className'
//In a separate Style Sheet
.header{
padding-top : 1em;
font-family : Palatino;
background-color : aliceblue;
};
const MyHeader=()=>(
<h3 className="header">
Styling in React
</h3>
);
- Maintaining Global Style Sheets at scale
- Cascading and specificity become less easy to predict
- Components styles are dependent on a global style sheet, difficult to reuse component
- Central point for Styles
- Access to Pseudo Selectors, Media Queries, and Animations
- Central point for Styles
Pros
Cons
Global CSS
Styling in React
Import CSS
Import CSS
import './my-header.css';
const MyHeader=()=>(
<h3 className="header">
Styling in React
</h3>
);
/* my-header.css */
.header {
font-family: "Comic Sans"
}
one "imported" .css file per component
- Components are not dependent on a global styles sheet.
- Components styles come with it
- Registers a static dependency
- Requires a specific Build Configuration
- Dev Team must implement a naming convention such as BEM to prevent naming collisions
- Why not Automate naming conventions?
Pros
Cons
Import CSS
Styling in React
CSS Modules
CSS Modules
like import css but no name collisions
import styles from './my-header.css';
const MyHeader=()=>(
<h3 className={styles.header}>
Styling in React
</h3>
);
/* my-header.css */
.header {
font-family: "Comic Sans"
}
- CSS scoped to the Component
- Class names are made unique for me
- Requires a specific build tool configuration
- All Classes are built into a single CSS file no matter if you need them or not
- Components are not 100% portable
Pros
Cons
CSS Modules
Styling in React
"CSS-in-JS"
💪
CSS-in-JS
CSS is written in the JS and the CSS is injected into the styled tag in the head of the document
import styled from 'styled-components';
const Header = styled.h3`
padding-top : 1em;
font-family : Palatino;
background-color : aliceblue;
`;
const MyHeader= () => (
<Header>
Styling in React
</Header>
);
- No specific build tool configuration needed
- Class names are generated for me
- Components are 100% portable
- Values can be Dynamically Assigned
- "Theme"ing available
- Critical Path CSS
- It's different*
- Lose the potential benefit of a cached stylesheet*
- Market churn
Pros
Cons
"CSS-in-JS"
styling
lab
Resources
Components with State
ReactJS
The Counter
class Counter extends React.Component {
state = {
count: 0
}
handleReset = () =>
this.setState({ count: 0 });
handleIncrement = () => {
this.setState(state => ({
count: state.count + 1
}))
}
render() {
const { count } = this.state;
return (
<div>
<strong>{count}</strong>
<button onClick={this.handleReset}>reset</button>
<button onClick={this.handleIncrement}>+</button>
</div>
)
}
}
Remote State?
class Counter extends React.Component {
state = {
results: []
}
handleFetch = () => {
fetch("http://example.org/something")
.then( res => res.json() )
.then( results => this.setState({ results }) )
}
render() {
const { results } = this.state;
return (
<div>
<button onClick={this.handleFetch}>Fetch!</button>
{results.map(item => <Other {...item} />)}
</div>
)
}
}
stateful-components
lab
Lifecycle Events
ReactJS
Each component has several “lifecycle methods” that you can override to run code at particular times in the process.
- Methods prefixed with will are called right before something happens.
- Methods prefixed with did are called right after something happens.
These methods are called when an instance of a component is being created and inserted into the DOM:
- constructor()
- componentWillMount()
- render()
- componentDidMount()
Mounting
An update can be caused by changes to props or state. These methods are called when a component is being re-rendered:
- componentWillReceiveProps()
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
Updating
This method is called when a component is being removed from the DOM:
- componentWillUnmount()
Unmounting
This method is called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.
- componentDidCatch()
Error Handling
lifecycle-methods
lab
Resources
- https://reactjs.org/docs/react-component.html#mounting
UI Events
ReactJS
Pass functions instead of strings
<!-- The HTML Way -->
<button onclick="recordLike()">
Click if you like!
</button>
// The React Way
<button onClick={this.recordLike}>
Click if you like!
</button>
Differences
- Have event handlers as React class methods
- Allows for full encapsulation
class LikeButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this.props.thankYouMessage);
}
render () {
return (
<button
onClick={this.handleClick}
thankYouMessage="Thanks for your like!"
>
Like
</button>
);
}
}
class LikeButton extends React.Component {
// Without Binding...
//constructor(props) {
// super(props);
// this.handleClick = this.handleClick.bind(this);
//}
handleClick() {
console.log(this.props.thankYouMessage);
// ...Uncaught TypeError: Cannot read property
// 'props' of undefined
}
render () {
return (
<button
onClick={this.handleClick}
thankYouMessage="Thanks for your like!"
>
Like
</button>
);
}
}
Gotcha: Bind member functions for the correct 'this'
class LikeButton extends React.Component {
// No binding needed. `handleClick` is auto-bound
// to LikeButton's `this`.
handleClick = () => {
console.log(this.props.thankYouMessage);
}
render () {
return (
<button
onClick={this.handleClick}
thankYouMessage="Thanks for your like!"
>
Like
</button>
);
}
}
... Or just use the Class Field Declaration syntax
event.target
const ActionLink = () => {
const handleClick = (event) => {
// 'event' has lots of useful data
console.log(event.target.href); // logs "#"
console.log(event.target.nodeName) // logs "A"
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
Access the Event's Origin Element?
See also: React Synthetic Events, Native DOM Events
<!-- The HTML Way -->
<a href="#" onclick="console.log('The link was clicked.'); return false">
Click me
</a>
Use e.preventDefault() instead of "return false;"
Preventing Default HTML Behavior
// The React Way
const ActionLink = () => {
const handleClick = e => {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
events
lab
Resources
- https://reactjs.org/docs/handling-events.html
- https://www.w3schools.com/jsref/dom_obj_all.asp
Forms in React
ReactJS
HTML Forms
HTML Forms typically manage their own state. For example, a text element contains it's own value (state).
React Forms
React form elements can be either controlled or uncontrolled.
Controlled Forms
The value of form elements are controlled via state.
class Form extends React.Component {
state = {
value: ""
}
handleChange = e =>
this.setState({ value: e.target.value });
render() {
const { value } = this.state;
return (
<input onChange={this.handleChange} value={value} />
);
}
}
Prefer Controlled
This allows the conversion of user input into data of any shape and allows for friendlier user feedback and validation.
forms
lab
Interacting with the DOM
ReactJS
`ref`
On occasion, you will need access to a DOM element. This is common when performing imperative actions on an element or integrating with 3rd-party libraries.
class AutoFocus extends React.Component {
componentDidMount() {
this.node.focus();
}
handleRef = node => {
this.node = node
}
render() {
return <input ref={this.handleRef} />
}
}
Smells
- Avoid using refs for anything that can be done declaratively
- Don't overuse refs
refs
lab
Resources
Sharing State
ReactJS
"Lifting State Up"
- often, several components need to reflect the same changing data.
- problem: who "owns" the state?
solution: lift state to closest, common ancestor
provide a single source of truth
lifting-state
lab
Resources
Render Props
ReactJS
Render Props
Component A takes a thing to render as a prop, does its work, and then renders said thing with results of its work.
<Network
render={({ online }) =>
<p>You are online: {online ? 'Yep' : 'Nope'}.</p>
}
/>
example via react-network
https://github.com/ReactTraining/react-network
Render Props
export default class Network extends Component {
static defaultProps = {
render: () => null,
onChange: () => {}
}
state = {
online: window.navigator.onLine
}
componentDidMount() {
window.addEventListener("offline", this.handleChange)
window.addEventListener("online", this.handleChange)
this.props.onChange(this.state)
}
componentWillUnmount() {
window.removeEventListener("offline", this.handleChange)
window.removeEventListener("online", this.handleChange)
}
handleChange = () => {
const online = window.navigator.onLine
this.props.onChange({ online })
this.setState({ online })
}
render() {
return this.props.render(this.state)
}
}
"Function-as-Child"
<Network>
{({ online }) =>
<p>You are online: {online ? 'Yep' : 'Nope'}.</p>
}}
</Network>
sometimes: "Render-Callbacks"
render-props
lab
Resources
Rendering null
ReactJS
More than Markup
React is great at creating visual components, but that's just scratching the surface
<MediaQuery
query="(min-width: 800px)"
onChange={this.handleScreenChange}
/>
<LockScreen active />
<Hotkey
combo="Ctrl+p"
onHotkey={this.handleHotkey}
/>
render-null
lab
Higher Order Components
ReactJS
Higher Order Components
- an advanced technique in React for reusing component logic
- a higher-order component transforms a component into another component
- use for "cross-cutting" concerns
Example
Many components need strings.
const ComponentA = ({strings}) => (
<h1>{strings.welcomeMessage</h1>
);
const ComponentB = ({strings}) => (
<h1>{strings.goodByeMessage</h1>
);
Example
A HOC that specializes in providing strings
const withStrings = Component => {
const strings = magicallyGetStrings();
return props => (
<Component
{...props}
strings={strings}
/>
);
}
More Complex Example
A HOC that provides fetch data
const withFetchData = url => Component => {
return class extends React.Component {
state = { data: null };
componentDidMount() {
fetch(url)
.then( res => res.json() )
.then( data => this.setState({ data }) )
}
render() {
const { data } = this.state;
return !data
? null
: (
<Component
{...this.props}
data={data}
/>
);
}
}
}
higher-order-component
lab
Composition
ReactJS
Composition
- React has a power composition model
- use composition instead of inheritance to share functionality
- create complex UIs via composition of simple, single purpose components
Example
const Modal = ({ active, children, onCloseGesture, ...props }) => (
<ModalMask {...props} active={active} onClick={onCloseGesture}>
<Lock active={active} />
<KeyDown keys={{ Escape: active && onCloseGesture }}>
<Card onClick={capture} onKeyDown={capture}>
{children}
</Card>
</KeyDown>
</ModalMask>
);
explain this?
Lab
the final project is this lab 🙂
Redux
Part 3
What is Redux?
Redux
What's Redux?
- Literally? Redux is a small JavaScript library that provides several helper methods for managing application state.
- The bulk of "Redux" is actually just simple, functional JavaScript functions used in a certain paradigm.
- Redux defines itself as a predictable state container for JavaScript apps.
- Redux makes you think of your application as an initial state being modified by a sequential list of actions.
Safe Global State
When to Redux?
Redux
When to Redux?
3 Pillars
Redux
1. Single Source of Truth
all Redux State is stored in a single object
const state = {
books: {
id1: {
id: "id1",
name: "Green Eggs and Ham"
}
},
claps: {
id1: 10
}
};
2. State is Read Only
no setters. changes are made by emitting actions describing what happened.
const action = {
type: "BOOK_CLAP",
payload: {
id: "id1"
}
}
3. Changes via Pure Functions
actions flow through reducers which optionally produce new state
const claps = ( state = {}, { type, payload } ) => {
switch( type ) {
case "BOOK_CLAP": {
const { id } = payload;
return {
...state,
[id]: state[id] ? state[id] + 1 : 1
}
}
default:
return state
}
}
The Parts
Redux
Redux Birds Eye
Action Object
const action = {
type: "BOOK_CLAP",
payload: {
id: "id1"
}
}
const createClap = (id) => ({
type: "BOOK_CLAP",
payload: { id }
});
Action Creator
Actions
type is required
Reducers
const claps = ( state = {}, { type, payload } ) => {
switch( type ) {
case "BOOK_CLAP": {
const { id } = payload;
return {
...state,
[id]: state[id] ? state[id] + 1 : 1
}
}
default:
return state
}
}
always return new memory reference when change occurs
Selectors
const selectBookById = (state, id) => {
const book = state.books[id];
const claps = state.claps[id] || 0;
return {
...book,
claps
}
}
optional but recommended helpers to grabbing parts from state
Redux Middleware
- extends capability
- logging
- dev tools
Creating a Store
import { createStore, combineReducers } from "redux";
import { books, claps } from "./reducers";
import { selectBookById } from "./selectors";
import createClap from "./actions";
const rootReducer = combineReducers({ books, claps });
const store = createStore(rootReducer);
const unsubscribe = store.subscribe( () => {
const state = store.getState();
console.log( selectBookById(state, "id1") );
});
store.dispatch( createClap("id1") );
unsubscribe();
redux
lab
React+Redux
Redux
Redux
Notifies subscribers when its state changes
React
Changes the UI when props or state changes
Simple Integration
import React from "react";
import store "./app/store";
class ConnectedComponent extends React.Component {
componentDidMount() {
this.unsub = store.subscribe( () => {
const state = store.getState();
const stuffICareAbout = selectMyStuff(state);
this.setState({stuffICareAbout});
})
}
componentWillUnmount() {
this.unsub();
}
// ...
}
aka naive
React-Redux Binding
import { connect } from "react-redux";
import { createClap } from "./app/store/actions";
import { selectBooks } from "./app/store/selectors";
import BookView from "./app/components/BookView";
const mapStateToProps = state => ({
books: selectBooks(state)
});
const bindActionsToDispatch = { createClap };
const storeConnector = connect(
mapStateToProps,
bindActionsToDispatch
);
export default storeConnector( BookView );
the connect HoC
NextJS Redux Wrapper
// in one of your NextJS pages
import withRedux from "next-redux-wrapper";
import { initStore } from "./app/store/storeFactory";
import { createClap } from "./app/store/actions";
import { selectBooks } from "./app/store/selectors";
// Your page component...
const View = () => ();
const mapStateToProps = state => ({
books: selectBooks(state)
});
const bindActionsToDispatch = { createClap };
export default withRedux(
initStore,
mapStateToProps,
bindActionsToDispatch
)(View);
the withRedux HoC
Next JS
quick tour
Final Project
lab
Reading List
Reading List
-
User searches for a title
-
Fetches data from Google Book API
-
Displays Book Data in Tile
- User can mark a book as read, or delete it altogether
Components
-
<App />
-
<Heading />
-
<BookSearch />
-
<Stack />
-
<Tile />
-
<QuickForm />
-
<Icon />
React Training
By Jared Anderson
React Training
- 2,391