busy developer's workshop: react - neward & associates · format lecture/lab format –i...

Post on 20-Jun-2020

10 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Busy Developer's Workshop:React

Ted Neward

Neward & Associates

http://www.tedneward.com | ted@tedneward.com

Before we begin...

Please make sure you have...– installed Git

https://git-scm.org/downloads/

– installed NodeJS

https://nodejs.org/en/

– installed VisualStudio Code

https://code.visualstudio.com/download

– these slides are available at

http://www.newardassociates.com/slides/Workshops/React.pdf

– the GitHub project to follow is at

https://www.github.com/tedneward/ReactWorkshop

Objectives

In this workshop, we're going to...– make sure your JavaScript is up to speed

TypeScript is also usable, but out of scope for us

– go over the basics of React

•components•JSX syntax•state, props and fields

– briefly discuss some advanced concepts

•higher-order components•context•hooks

Format

How we gonna do this?

Format

Lecture/lab format– I will lecture for a bit

– You will code/debug/explore for a bit

I will try to wander the room and help where I can

– Lather, rinse, repeat

– Turn in your evals and you are free!

Format

"The Rules"– Pairing and interaction

absolutely encouraged

– Googling/Binging/looking stuff up online

absolutely encouraged

– Leaving the room during a "lab"

absolutely encouraged (if necessary)

– Jumping ahead

encouraged, but I can only help for "this" step

Format

"Requests"– set the phone/volume/etc to vibrate

basically, don't disturb the neighbors

– ask questions!

if you're thinking it, so are other people

– ... but let's keep the focus to the here and now

there's a lot to cover, so I need to keep us focused

Format

Ready?– Any questions?

– If not, here we go....

– Last chance... abandon hope, all ye who remain...

ECMAScript 2016

Language core

ECMAScript Overview

Overview

ECMAScript has ...– ... an imperative C-family-of-languages syntax

– ... a classless object system

– ... functional objects

– ... loosely-typed type system

– ... a metaobject protocol

– ... a garbage collected object heap

– ... and a few bad design decisions/legacy

ECMAScript Basics

Getting the tiny bits out of the way

Basics

Starting points– Whitespace: space, tabs, CRLF, etc

mostly irrelevantline terminator (";") mostly optional

– Comments: // (end-of-line) and /* */ (multi-line)

– Identifiers/Names: [A-Za-z][A-Za-z0-9...]

Basics

Built-in types understood– Booleans: true, false

other values devolve into "truthy" and "falsy"

– Numbers: always a 64-bit floating-point type, NaN

•Binary literals

0b111110111 (503 decimal)

•Octal literals

0o767 (503 decimal)

– Strings: 16-bit Unicode

– Objects: bag of name-value pairs

– Functions: invokable code

– null, undefined

Basics

Template Strings– "Backticked" strings

•backtick character is now a new string literal delimiter•backticked-strings are multiline-aware

– Strings now support an "interpolation" form

•similar to Python, Perl, Ruby, etc•use ${name}-qualified identifiers•combines with backticks very nicely

Basics

Template Strings

// String interpolationvar name = "Bob", time = Date.now();console.log(`Hello ${name}, how are you ${time}?`);

Basics

Variables– signified with keyword, followed by legal name

– any variable used without keyword-based declaration is global

this is generally considered badbe particularly careful in "for" loops

– variables are typeless

but the things they point to are typedjust not very strongly; coercion is always possible

Basics

var vs let vs const– var is a mutable variable declaration

function-scoped

– Let is a mutable variable declaration

block-scoped

– Const is an immutable variable declaration

block-scoped

Basics

var, let and const

function f() {w = 12; // global! bad!{

let x;{

// okay, block scoped nameconst x = "sneaky";// error, const//x = "foo";

}// error, already declared in block//let x = "inner";var y = "Fred";z = 12;

}}

Basics

Arrays– untyped collections of values/variables in indexed order

– instantiated with []

– accessed via [], zero-indexed

Basics

Array use

let strings = ["This", "is", "an", "array","of", 5, "strings"

];console.log(strings[0]); // Prints "This"console.log(strings[5]); // Prints "5"

Basics

Destructuring Assignment– "pick out" parts of an object and assign to values

– common in a number of functional languages

– used with both objects and arrays (positional assignment)

– can also be used in function parameters

Basics

Destructuring Assignment

var [a, b, c, d] = ['hello', ', ', 'world', 'ignored'];console.log(a + b + c);

// Some interesting objects we're working withvar pt = {x: 123, y: 444};var rect = {topLeft: {x: 1, y: 2}, bottomRight: {x: 3, y: 4}};

var {x, y} = pt; // unpack the pointvar {topLeft: {x: x1, y: y1}, bottomRight: {x: x2, y: y2}} = rect;

console.log(x, y);console.log(x1, y1, x2, y2); // 1,2,3,4

// Can be used in parameter positionfunction g({name: x}) {

console.log(x);}g({name: 5});

Basics

Operators– operator set similar to that from C-family langs

but there are some subtle and dangerous differences!

– + - * / % : mathematical operators

– <= >= != < > : comparison operators

– === !== : equality/inequality operators

ES also supports == and !=, but they attempt conversion

– && || ! : logical operators

– typeof : returns type of object

object, function, undefined, Number, String, ...

Basics

What's truthy? What's falsy?

0 == '''' == '0'false == '0'false == nullnull == undefinedfalse == undefined

Basics

What's truthy? What's falsy?

0 == '' (true)'' == '0' (false)false == '0' (true)false == null (false)null == undefined (true)false == undefined (false)

ECMAScript Flow Control

if, while, for, etc

Flow Control

if: boolean decision-branching– "truthy" values execute block

– "falsy" values skip block

•"else" block executed, or...•"else if" condition examined, or ...•we just drop to the next statement

Flow Control

while: boolean decision-looping– "truthy" values execute the loop body

– "falsy" values drop to the next statement

– "do-while" just puts the conditional at the bottom of the loop body

Flow Control

for: condition-terminating loop– "traditional" for (initialize/conditional/increment)

– "for-in" iteration

iterates over the properties/elements in the collection/object

– "for-of" iteration

iterates over the keys in the collection/object

Flow Control

Iterators and for-of– Custom iteration a la CLR IEnumerable or Java Iterable

– Use "for ... of" similar to "for ... in"

– No actual collections required, just an object that follows the Iterable protocol

•object must have a next() method•return from the next() method must have a "done" and "value" field

Flow Control

Iterators and for-of

for (let element of [1, 2, 3]) {console.log(element);

}

let fibonacci = {[Symbol.iterator]() {

let pre = 0, cur = 1;return {

next() {[pre, cur] = [cur, pre + cur];return { done: false, value: cur }

}}

}}

Flow Control

Iterators over generic array

function iterateElements(array) {return {

[Symbol.iterator]: function() {var index = 0;var current;return {

next: function() {if (index < array.length) {

current = array[index++];return { done:false, value: current };

}return { done:true, value: current };

}};

}};

}

let numbers = [1, 2, 3, 4, 5, 6];for (let n of iterateElements(numbers)) {

console.log(n);}

ECMAScript Functions

Functions

Functions syntax– composition: 4 parts

"function"name (optional)parameter set (0 - n named arguments)statement block

– function can appear anywhere an expression is expected

top-level, as object members, nested, and so onnested functions have access to their enclosing scope

Functions

Function "interesting" notes– functions are objects, too

– two implicit arguments to every function invocation

'this': reference whose contents vary with invocation pattern'arguments': array of arguments passed in

– unlike other languages, functions don't enforce arity

missing arguments are undefined, extras are in 'arguments'

Functions

Functions

function addIt(first, second) {return first + second

}println(addIt(1, 2))

var addItAgain = function(first, second) {return first + second

}println(addItAgain(1,2))

println(function(first, second) {return first + second

}(1, 2))

var add = function() {var result = 0;for (var i = 0; i<arguments.length; i++)

result += arguments[i]return result

}println(add(1, 2, 3, 4, 5))

Functions

Function invocation patterns– Function Invocation: function is not an object member

"this" is bound to the global object

– Method Invocation: function is an object member

"this" is bound to object on which function is being invoked

– Apply Invocation: function is invoked explicitly via apply()

"this" is bound to first argument in parameters list

– Constructor Invocation: function is used as a constructor

new object created with hidden link to function's prototype"this" is bound to newly-created object

Functions

Default, rest and spread parameters– set default values (for when no value is passed)

– "rest" parameters are an array capturing all remaining arguments

– "spread" parameters "spread" an array into multiple parameter slots

Functions

Default parameters

// Defaultsfunction slice(list, indexA = 0, indexB = list.length) {

// ...}

Functions

Rest parameters

// Rest paramsfunction push(array, ...items) {

items.forEach(function(item) {array.push(item);

});}var a = [];push(a, "1", "2", "3", "4", "5");console.log(a);

Functions

Spread parameters

function add(x, y) {return x + y;

}

var numbers = [4, 38];console.log(add(...numbers)); // 42

// Also works for array literalsvar a = [1];var b = [2, 3, 4];var c = [6, 7];var d = [0, ...a, ...b, 5, ...c];console.log(d);

Functions

Functions are objects– as such, have methods defined on them for manipulating

functions

defined in Function prototype

– bind()

provides a new "this" reference for method invocation

– apply()

use of the () operator on an object attempts to invoke apply()

Functions

Closures– referenced values remain around as long as function does

the function "closes over" the reference variable (hence the name)

– the actual link isn't explicit or discoverable

this provides opportunities to "hide" members from the object on which a function operates, to avoid pollution

Functions

Closures

var myObj = function() {var value = 0;return {

increment: function(inc) {value += typeof inc === 'number' ? inc : 1;

},getValue: function() {

return value;}

};}();myObj.increment()println(myObj.getValue())for (var m in myObj)

println(m + " = " + myObj[m])myObj.value = 10println(myObj.getValue())

Functions

Higher-order functions– passing functions into functions

– examples: Array.map, .filter, etc

Functions

Closures

var evens = [2, 4, 6, 8];var odds = evens.map(function (v) { return v + 1 });var nums = evens.map(function (v, idx) { return v + idx } );var pairs = evens.map(function (v) { return {even: v, odd: v + 1} } );

Functions

Arrow functions– lexical "this" binding

– shorter syntax

intended for anonymous/lambda usage

Functions

Arrow function syntax

// Lexical thisvar bob = {

_name: "Bob",_friends: [],printFriends() {

this._friends.forEach(f =>console.log(this._name + " knows " + f));

}}bob._friends.push("Fred");bob.printFriends();

Functions

Arrow function syntax

// Expression bodiesvar evens = [2, 4, 6, 8];var odds = evens.map(v => v + 1);var nums = evens.map((v, idx) => v + idx);var pairs = evens.map(v => ({even: v, odd: v + 1}));console.log(odds);console.log(nums);console.log(pairs);

Functions

Arrow function syntax

// Statement bodiesvar fives = [];nums.forEach(v => {

if (v % 5 === 0)fives.push(v);

});console.log(fives);

ECMAScript classes and objects

Prototypical object-oriented programming

Objects

Objects are essentially a bag of name-value pairs– values can be either data or function values

– classless system: no concept of "class", just "objects"

– "open" objects: members can be added/removed

– members accessed through refinement operators (. [])

– use [] to access illegal identifier names (as keys)

Objects

Objects

var speaker = {'firstName' : 'Ted','lastName' : 'Neward',sayHello : function() {

println("Hello!")},sayHowdy : function() {

println("Howdy!")}

}println(speaker.firstName)println(speaker["lastName"])speaker.sayHowdy()speaker["sayHello"]()

for (var m in speaker) {println(m + "=" + speaker[m])

}

Objects

Object prototypes– objects always have a "prototype" object

– prototype is always in scope when resolving names

– this creates a "prototype chain" of names

– we can control the prototype used at construction ...

... but the syntax for doing so in ECMAScript is... complicated.

– instead, monkey-patch Object and add a create() method

Objects

Objects and prototypes

var empty = { }for (var m in empty) {

println(m + "=" + empty[m])}println(empty.toString())

Objects

Monkey-patching

if (typeof Object.create !== 'function') {Object.create = function(proto) {

var F = function() {};F.prototype = proto;return new F();

};}

var base = {sayHowdy : function() { println("Howdy") }

}var derived = Object.create(base)for (var m in derived) {

println(m + "=" + derived[m])}derived.sayHowdy()

Objects

Monkey-patching

// Method to add a method to any particular prototypeFunction.prototype.method = function (name, func) {

if (!this.prototype[name]) {this.prototype[name] = func;

}return this;

};// add an 'roundOff' method to NumberNumber.method('roundOff', function() {

return Math[this < 0 ? 'ceil' : 'floor'](this);});println((5.2).roundOff())println((-12.2).roundOff())

Objects

Classes– constructors

– instance and static members

static fields/methods are on the prototype object

– fields (properties)

– methods

– simple sugar over prototype-based OO

•still prototype-based inheritance•"super" calls to prototype

Objects

Classes

class Monster extends Character {constructor(x, y, name) {

super(x, y);this.name = name;this.health_ = 100;

}

attack(character) {super.attack(character);

}

get isAlive() { return this.health_ > 0; }get health() { return this.health_; }set health(value) {

if (value < 0) throw new Error('Health must be non-negative.');this.health_ = value;

}}

Objects

Enhanced Object literals– bring class declarations and object literals closer together

•set the prototype at construction•shorthand syntax for same-name assignments•defining methods•making super calls•compute property names with (runtime) expressions

ECMAScript 6 Classes

Object initializer shorthand

var handler = function() {console.log("Handled!");

};var theProtoObj = {

name: "Proto"};var obj = {

// __proto____proto__: theProtoObj,// Shorthand for 'handler: handler'handler,// MethodstoString() {

// Super callsreturn "d "; // + super.toString();

},// Computed (dynamic) property names[ 'prop_' + (() => 42)() ]: 42

};obj.handler();console.log(obj.toString());console.log(obj.prop_42);

ECMAScript modules

Organizing/structuring code

Modules

ECMAScript wants to allow for structuring of code– ... without specifying concrete (loading) details

– modules are essentially at file scope

Modules

Imports and exports– to make a symbol available from the module, "export" it

– to use a symbol exported from another file, "import" it

•multiple imports from the same file use a {} syntax to pull each directly•you cannot blanket-import all exported symbols from a module (by design)•you can import all exported symbols from a module by giving them a top-level name

Modules

Module usage

// lib/math.jsexport function sum(x, y) {

return x + y;}export var pi = 3.141593;

// app.jsimport * as math from "lib/math";alert("2π = " + math.sum(math.pi, math.pi));

// otherApp.jsimport {sum, pi} from "lib/math";alert("2π = " + sum(pi, pi));

NPM

Node Package Manager

npm

Node doesn't have everything "out of the box"– in fact, there is less in the box than expected

– fortunately, the box comes with a "grow the box" tool

npm

npm: Node Package Manager– command-line tool to install/manage node packages

– full list of packages is at http://search.npmjs.org/

WARNING: this is a huge list, some are good, some are crapBetter to know what you want before hunting for it

– Must be online to use npm!

because it pulls package sources from npmjs.org, so...

npm

npm installs to a directory– node_modules/

– generally, treat this as opaque

•toying with this can open a huge Pandora's box•if it gets wedged, just nuke it and re-install

– "global" installs will install to a user/system-wide directory

varies with platform

npm

npm commands:– all take a "-g" parameter to mean "global"

globally will (sometimes) require admin rights

– npm help {command}: man page on {command}

– often two forms:

•long name: "remove"•unix-style alias: "rm"

npm

npm init– creates npm manifest (package.json)

•describes dependencies•describes dev-only dependencies•describes entry point script•describes other scripts•... and so on

– JSON format

package.json

package.json

{"name": "sample-app","version": "1.0.0","description": "Sample application","main": "app.js","dependencies": {

"debug": "^2.2.0"},"devDependencies": {},"scripts": {

"test": "node --debug app.js"},"author": "Ted Neward","license": "ISC"

}

npm

npm install– npm install {package}

•downloads package to node_modules•if "--save" or "--save-dev" is provided, saves to manifest

– npm install

•examines manifest•downloads all packages locally•typically used to set up code for execution

– there may be binaries/scripts installed

use "npm bin" to find out where

npm

npm ls / npm list / npm ll– list the packages installed

g will list all global packages installed

– ll will list in a "long" format

includes some additional info about the package

npm

npm upgrade / npm up– upgrade app dependencies to latest version

– subject to manifest's versioning declarations

•"^" dependencies will be upgraded to whatever's latest•"~" dependencies will only upgrade to latest minor version•so "^1.1.1" will upgrade to 1.1.2, 1.2.0, or 2.0•but "~1.1.1" will upgrade to 1.1.2, but not 1.2.0 or 2.0

– use "--save" to record new versions in manifest

npm

npm remove / npm rm– removes the package from the application

– use "--save" to record removal in the manifest

npm

npm {command}– "npm run" or "npm test" or ...

– directly corresponds to the "scripts" section in manifest

– commonly used as a lightweight build tool

•"npm test" to launch automated tests•"npm run" to kick off application execution

npm

npm explore {package}– open a shell in node_modules for {package}

– avoids having to resolve by hand

useful for package debugging

– not often used by non-package developers

npm

Note: if npm fails– npm will display output to console window

– it will attempt to carry on

– it will write all output to "npm-debug.log" in current directory

Modules

Some interesting modules to explore:– Express: Web framework

– Sequelize: RDBMS access module

– Passport: User-authentication

– More--see https://npmjs.org

Break time!

Take a few to brace yourself

React Basics

Getting started

React

What is it?

React

A user-interface platform for HTML/Web– "just the V in MVC"

– leverages custom features of Javascript

– component-oriented

UI inside the component code (JSX)

– open-source

– built by Facebook

Getting Started with React

From zero to Hello World!

Getting Started

Prerequisites– NodeJS

– text editor of some form

VisualStudio Code is popular

– a Web browser

Getting Started

Install the prerequisites

npm install -g create-react-app

Getting Started

Scaffold out

create-react-app hello-world

Getting Started

Starting

npm start

Bundle the app into static files

npm run build

Run the rest runner

npm test

Getting Started

index.js

import React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import registerServiceWorker from './registerServiceWorker';

ReactDOM.render(<App />, document.getElementById('root'));registerServiceWorker();

Getting Started

App.js

import React, { Component } from 'react';import logo from './logo.svg';import './App.css';

class App extends Component {render() {

return (<div className="App">

<header className="App-header"><img src={logo} className="App-logo" alt="logo" /><h1 className="App-title">Welcome to React</h1>

</header><p className="App-intro">

To get started, edit <code>src/App.js</code> and save to reload.

</p></div>

);}

}

export default App;

Getting Started

JSX, ES2015, and React– React uses JSX as its language of choice

•JSX is an ECMAScript + XML variant•transpiled by Babel (among others)•helps to unify code and markup

– not required

anecdotally, most React devs seem to be using it

– bear in mind, JSX is not HTML

•JSX is transformed into ECMAScript•... which is then executed in the browser•there may be some oddities in behavior because of this•consider examining the transpiled source

Getting Started

Installing Babel

npm install -g babel-cli

Installing some nice Babel pre-set configuration

npm install -g babel-preset-es2015 babel-preset-react

Set up Babel presets in .babelrc

{"presets": [ "es2015", "react" ]

}

Getting Started

Hello world– Scaffolded app doesn't say much

– the Gods of Computer Science demand their recognition!

Getting Started

Hello world– a single text message saying, "Hello" to the world

– component-oriented: we need a "hello" component

could abstract this further, to be a "message" or "text" component, if desired

Getting Started

Hello component– properties: the message to display

•we could go crazy and add others, like style, font, etc•this will not change after initialization/instantiation

– behavior: none

– events: none

Getting Started

Hello

import React from 'react';

export class Hello extends React.Component {render() {

return (<div>{this.props.message}</div>)}

}

Getting Started

In App.js, import Hello

import { Hello } from './Hello';

In App.js, use it

<p className="App-intro">To get started, edit <code>src/App.js</code> and save to

reload.</p><Hello message="Hello, world!" />

Hands-On Time!

Part 1: React scaffolding!

HOT Pt 1

Part 1: React scaffolding– create new React app (rjoke)

– make sure it runs (both the tests and the app)

– build, import and use the Joke class

React Basics

Going into what React is and does

React Concepts

What you must know

Concepts

Declarative (over imperative)– React wants to tap into the declarative paradigm

say "what" instead of "how"

– heavily inspired by functional programming

which is often said to be synonymous with declarative(although it's possible to be declarative without being functional)

Concepts

Elements– "the smallest building blocks of React apps"

– immutable objects

– represent a DOM node

– can (and usually do) have multiple children

– contain only the information necessary to represent the interface

Concepts

Components– components are not objects

•or, at least, not strictly objects•React holds that functions can be objects too

– components are standalone units of state, behavior and notification

think objects without implementation inheritance

– reuse is through composition

not inheritance

Concepts

Unified– in other words, everything related to a component should

live inside that component

•code•UI rendering instructions•state/properties

– this flies in the face of "split" frameworks (like Angular or Vue)

Concepts

Rendering– each React component will "render" its UI on demand

– think of this as a function:

f(S) -> UI (where S is "state")

– this is how React will manage immutable UI controls

this can also help optimize UI refreshes

– Facebook encapsulated this into Flux

"a unidirectional flow of data"

Concepts

Virtual DOM– React builds a hidden "copy" of the DOM

– then compares the virtual DOM to the real one

– much more efficient than rendering directly to the browser DOM

– this also simplifies testing

JSX

React's expression syntax

JSX

JSX is entirely syntactic sugar– Not required

– wrapper around React.createElement()

– not a formal language; just something React recognizes and transpiles

not to be confused with E4X from a decade ago

JSX

JSX has to be able to determine what is React, what is HTML– React elements must be transpiled

– HTML elements must be passed through to the browser

– therefore, React types must be first-letter-capitalized

– MUST return a single-rooted (as in XML) tree

JSX

WRONG

import React from 'react';

// Wrong! This is a component and should have been capitalized:function hello(props) {

// Correct! This use of <div> is legitimate because // div is a valid HTML tag:return <div>Hello {props.toWhat}</div>;

}

function HelloWorld() {// Wrong! React thinks <hello /> is an HTML tag // because it's not capitalized:return <hello toWhat="World" />;

}

JSX

Corrected

import React from 'react';

// Correct! This is a component and should be capitalized:function Hello(props) {

// Correct! This use of <div> is legitimate because // div is a valid HTML tag:return <div>Hello {props.toWhat}</div>;

}

function HelloWorld() {// Correct! React knows <Hello /> is a component // because it's capitalized.return <Hello toWhat="World" />;

}

JSX

JSX props expressions– any JS expression can be passed as a prop inside of {}

– statements (if, for, etc) are not expressions

to use these, capture their results into a local var

JSX

"Spread attributes" can be quite helpful– use "..." to pass the whole props object to child

components

– pick specific props to consume and pass the rest via spread operator

JSX

These two components are equivalent

function UseGreeting() {return <Greeting firstName="Ben" lastName="Hector" />;

}

function UseGreetingUsingSpread() {const props = {firstName: 'Ben', lastName: 'Hector'};return <Greeting {...props} />;

}

JSX

Extracting one prop, passing the rest

const Button = props => {const { kind, ...other } = props;const className =

kind === "primary" ? "PrimaryButton" : "SecondaryButton";return <button className={className} {...other} />;

};

const App = () => {return (

<div><Button kind="primary" onClick={() => console.log("clicked!")}>

Hello World!</Button>

</div>);

};

JSX

Choose the element type at runtime– assign the type to a variable

– use that variable in the React element type expression

JSX

Photo or Video?

import React from 'react';import { PhotoStory, VideoStory } from './stories';

const components = {photo: PhotoStory,video: VideoStory

};

function Story(props) {// JSX type can be a capitalized variable.const SpecificStory = components[props.storyType];return <SpecificStory story={props.story} />;

}

JSX

Child elements are passed in a special prop: props.children– bools, null and undefined are ignored; they don't render

– these can be string literals (string appears in props.children)

strings are trimmed and concatenated

– these can also be any ECMAScript expression

such as an array of objects

– can be a mix of HTML and React components

HTML will just be strings intermixed among objects

JSX

Children (React elements)

<MyContainer><MyFirstComponent /><MySecondComponent />

</MyContainer>

Children (String literals)

<MyComponent>Hello world!</MyComponent>

JSX

Conditional child rendering

<div>{showHeader && <Header />}<Content />

</div>

<div>{props.messages.length > 0 &&

<MessageList messages={props.messages} />}

</div>

JSX

Expressions as children

function Item(props) {return <li>{props.message}</li>;

}

function TodoList() {const todos = ['finish doc', 'submit pr', 'nag dan to review'];return (

<ul>{todos.map((message) => <Item key={message} message={message} />)}

</ul>);

}

JSX

Functions as children

// Calls the children callback numTimes to produce a repeated componentfunction Repeat(props) {

let items = [];for (let i = 0; i < props.numTimes; i++) {

items.push(props.children(i));}return <div>{items}</div>;

}

function ListOfTenThings() {return (

<Repeat numTimes={10}>{(index) => <div key={index}>This is item

#{index} in the list</div>}</Repeat>

);}

React Components

The building blocks of React

Components

React components– represent a union of state, behavior and notifications

– practically, a method ("render") to describe the DOM elements to be built

– divide neatly into "stateless" and "stateful"

meaning, "does the component preserve internal state"

– explicitly differentiate between "state" and "data parameters" ("props")

•state changes over time•props are used to customize the component at creation

Components

Components are designed for composibility– components will (frequently) have children (components)

– these children will often do some/much of the heavy UI lifting

•but with some customization and/or connection by the parent•children are accessible via this.props.children property

Components

A sample "breakdown" of the Twitter profile page

<HomePage><Avatar src={} ... /><UserInfo user={} ... /><Counts tweets={} following={} ... /><Tweets list={} ... />

</HomePage>

Components

Three main ways to create a React component– Stateless function components

– extend React.Component

– React.createClass()

createClass() is unofficially deprecated

Components

Stateless function components– function itself represents the rendering logic

in other words, the function is assumed to be the "render" function

– optionally takes a "props" parameter for passing in values for use

– cannot have any internal state

– no lifecycle methods

Components

Pure function taking no parameters

var HelloMsg = () => <h1>Hello, React!</h1>

Pure function taking parameters ("props")

var ClickableImage = props => (<a href={props.href}>

<img src={props.src} /></a>

);

Components

Extending React.Component– uses ES 6 class syntax

– properties are passed in to constructor (to "this.props")

– state is stored directly in constructor (to "this.state")

– all functions are defined using "normal" function syntax

Components

class HelloMsg extends React.Component {render() {

return <h1>Hello, React!</h1>}

}

class ClickableImage extends React.Component {constructor(props) {

super(props);// This constructor will trigger a warning about being unnecessary

}render() {

return (<a href={this.props.href}>

<img src={this.props.src} /></a>

);}

}

Components

Props vs state vs fields– "props" are React's passed-in parameter set from the

component instantiation/use

these should/will never change

– "state" is the internal state that reflects on the component's UI

this changes over time

– "fields" are anything that doesn't fit in the above two categories

fields will usually be interim calculations, cache, etc

– most React use will center around props and state (not fields)

Component Properties

Working with component properties more effectively

Component Properties

ECMAScript is an untyped language– strings, numbers, booleans, they're all just objects

– ECMAScript will quite happily accept anything

– React will offer up no warnings or errors when given the wrong type

string instead of a number, for example

Component Properties

A NumbersList component (function style)

const NumbersList = props => (<div>

{props.list.map(number =><div key={number} className={`highlight-${number === props.x}`}>

{number}</div>

)}</div>

)

Using it (incorrectly!)

<NumbersList list={[a, b, c]} x="42" />

This fails (silently)

Component Properties

React allows us to define "property types"– React will verify and flag when expectations are violated

– "propType" property on component

– array of React.PropType constants

– React will validate properties (by name) against propType definitions

and warn in browser console when violations are detected

Component Properties

React.PropTypes– array

– bool

– number

– object

– string

– func

Component Properties

React.PropTypes– node: anything that can be rendered

– element: a React element

– instanceof(SomeClass)

– oneOf([...]): for enumerated values

– oneOfType([...]): list of acceptable types

– arrayOf(type)

– objectOf(type): object with property values of a certain type

Component Properties

Customizations– by default, all props are optional

•flip to required with chained isRequired property•any any PropTypes value

– can also write a two-argument function

params: props (array of properties), propName

Component Properties

Adding propTypes to NumbersList

NumbersList.propTypes = {x: React.PropTypes.number

}

Component Properties

NumbersList defined as class

class NumbersList extends React.Component { static propTypes = {

x: React.PropTypes.number};

}

Component Properties

Default values for properties– "defaultProps" array contains default values for properties

– these are only used when no values are passed in

Componet Properties

An AlertBox component

const AlertBox = props => (<div className="alert alert-{props.level}">

{props.message}</div> );

AlertBox.defaultProps = {level: "danger"

};

Hands-On Time!

Part 2: React components!

HOT Pt 2

Part 2: Some simple components– create a Header and Footer component for the app's

chrome

– create a Joke component around a Joke object

– create a Jokelist component to display all the Jokes

More React Basics

Getting more sophisticated

React State Management

Understanding state in React

State Management

Three things to know about state– Do not modify state directly

always use setState()

– State updates may be asynchronous

React may batch them up into a single update for performance

– State updates are merged

the object passed to setState is merged with (not replacing) the current state

State Management

Countdown timer (as a class)

export class Timer extends React.Component {constructor(props) {

super(props);this.state = { counter: this.props.initialSeconds };

}

componentDidMount() {let currentCounter;this.timerId = setInterval(() => {

currentCounter = this.state.counter;if (currentCounter === 1) {

clearInterval(this.timerId);}this.setState({ counter: currentCounter - 1 });

}, 1000);}

render() { return (<div>{this.state.counter}</div>); }};

State Management

"The Data Flows Down"– neither parent nor child components should know if a

component is stateful or -less

– they shouldn't care if it is a function or class

– state is encapsulated--inaccessible to any component other than its owner

– any state is always owned by some specific component

– any data or UI derived from that state can only affect components "below" it

State Management

Some components will be state containers– they will hold state and use sub-components for display

– conditional rendering selects between which sub-components

– isn't strictly necessary but does embrace composition well

State Management

Display components

function UserGreeting(props) {return <h1>Welcome back!</h1>;

}

function GuestGreeting(props) {return <h1>Please sign up.</h1>;

}

State Management

State container component

export function Greeting(props) {const isLoggedIn = props.isLoggedIn;if (isLoggedIn) {

return <UserGreeting />;}return <GuestGreeting />;

}

State Management

Remember updates can be asynchronous– this means setState() calls may not have "this" available

– setState() calls may also be batched or merged

– if new state depends on old state, use callback version of setState to reference previous state

State Management

Incorrect implementation

incrementCount() {// Note: this will *not* work as intended.this.setState({count: this.state.count + 1});

}

handleSomething() {// Let's say `this.state.count` starts at 0.this.incrementCount();this.incrementCount();this.incrementCount();// When React re-renders the component, `this.state.count` will be 1,

not 3}

State Management

Incorrect implementation

incrementCount() {this.setState((prevState) => {

// Important: read `prevState` instead of `this.state` when updating.return {count: prevState.count + 1}

});}

handleSomething() {// Let's say `this.state.count` starts at 0.this.incrementCount();this.incrementCount();this.incrementCount();// At this line, this.state.count = 0// When React re-renders, this.state.count = 3

}

Events

Responding to changes in the universe

Events

Two kinds of events in the universe– React lifecycle events

– "External" events

Events

React lifecycle events– notifications about the component

•it is being initialized•it is being "mounted"•... and so on

– to receive, implement a method of the right name on the component

React will invoke it when appropriate

Events

React lifecycle events– componentWillReceiveProps:

component is about to receive new props array

– componentWill/DidMount:

fired before/after the component instance writes to the browser

– shouldComponentUpdate:

component needs to update to new state; return true to update, false to remain un-updated

– componentWill/DidUpdate:

fired when component receives new props or new state

– componentWill/DidUnmount:

fired before/after the component instance is removed from the browser

Events

A Clock component

export class Clock extends React.Component {constructor(props) {

super(props);this.state = {date: new Date()};

}componentDidMount() {

this.timerID = setInterval(() => this.tick(), 1000);}componentWillUnmount() {

clearInterval(this.timerID);}tick() {

this.setState({date: new Date()});}render() {

return (<div><h2>It is {this.state.date.toLocaleTimeString()}.</h2></div>);

}};

Events

React can respond to browser events– define a method/function on the class

will need to re-bind "this" in the class, usually the constructor

– for the HTML element, use an expression that describes the function to invoke

arrow function, reference to defined method, etc

– React normalizes all browser events into a "SyntheticEvent"

W3C cross-browser standard; underlying native event is available on the synthetic event as "nativeEvent"

– browser event is passed to event function as first parameter

usually called "e" or "event"

Events

Most common "external" events– Keyboard events

onKeyDown, onKeyPress, onKeyUp

– Focus events

onFocus, onBlur

– Form events

onChange, onInput, onSubmit

– Touch events

onTouchStart, onTouchEnd, onTouchMove, onTouchCancel

– Mouse events

onClick, onDrag, onMouseOver, onMouseOut, etc

– also see clipboard events, wheel events, media events, and more

Events

ToggleButton

export class Toggle extends React.Component {constructor(props) {

super(props);this.state = {isToggleOn: true};

// This binding is necessary to make `this` work in the callbackthis.handleClick = this.handleClick.bind(this);

}handleClick() {

this.setState(prevState => ({ isToggleOn: !prevState.isToggleOn }));

}render() {

return (<button onClick={this.handleClick}>

{this.state.isToggleOn ? 'ON' : 'OFF'}</button>

);}

}

Events

Sometimes we want to pass additional parameters– inside a loop it is common to want to pass an extra

parameter to an event handler

id of the row item or some equivalent

– two approaches work equally well:

•define an arrow function that takes the event parameter; invokes your method with additional parameter(s)•bind the event-handling function with the additional parameters directly

Events

Define an arrow function

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

Re-bind the event-handling function

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

Input

User input (forms) in React

Input

React allows standard HTML forms– for those cases where the standard HTML behavior "just

works"

– frequently, however, additional processing is desired/necessary

Input

Controlled components– in HTML, form elements usually hold their own state

– in React, mutable state is captured in components

– so let's capture the state in React as the "source of truth"

•which means updating it via React's setState() mechanism•and re-displaying it in each render() cycle

– NOTE: sometimes we will want to prevent default handling of an HTML event

such as form submission

Input

NameForm: render() logic

render() {return (

<form onSubmit={this.handleSubmit}><label>

Name:<input type="text" value={this.state.value}

onChange={this.handleChange} /></label><input type="submit" value="Submit" />

</form>);

}}

Input

NameForm: event-handling

export class NameForm extends React.Component {constructor(props) {

super(props);this.state = {value: ''};

this.handleChange = this.handleChange.bind(this);this.handleSubmit = this.handleSubmit.bind(this);

}

handleChange(event) {this.setState({value: event.target.value});

}

handleSubmit(event) {alert('A name was submitted: ' + this.state.value);event.preventDefault(); // Form submission will load a new page

normally}

React

HTML considerations– input/text: reference the text with ".value"

– textarea: same as input/text

– select: choose which option with a "value" attribute on the select tag

track choice selection using onChange

– use "name" attribute to discern between UI controls in an event-handler

Hands-On Time!

Part 3: Events and State

HOT Pt 3

Part 3: Adding event-handling and input– hide the punchline

– create a VoteCounter component to track upvotes of Jokes

or anything else; there's nothing Joke-specific about upvoting

– creating new Jokes

or editing old ones, if you so desire

More React

Beyond the basics

React Context

Passing state down

Context

Passing props down through a tree– each component has to participate

– this can be error-prone and problematic

– some components may not know to participate

Context

React solves for this with contexts– allows us to pass a value deep into the tree

– without explicitly threading it through each component

– creates implicit dependencies on context objects; use with care

Context

Using contexts– create a context with React.createContext(default_value);

– create a point of context use with Context.Provider and pass a value

– read from the context type to get the "nearest" (hierarchically) context value

Context

Create the context (and related data)

export const themes = {light: {

foreground: '#000000',background: '#eeeeee',

},dark: {

foreground: '#ffffff',background: '#222222',

},};

export const ThemeContext = React.createContext(themes.dark // default value

);

Context

Use the Context.Provider (pt 1)

import ThemedButton from './themed-button';

// An intermediate component that uses a ThemedButton// without having to know or pass theme from its parentfunction Toolbar(props) {

return (<ThemedButton onClick={props.changeTheme}>

Change Theme</ThemedButton>

);}

Context

Use the Context.Provider (pt 2)

import {ThemeContext, themes} from './theme-context';

class App extends React.Component {constructor(props) {

super(props);this.state = {

theme: themes.light,};

this.toggleTheme = () => {this.setState(state => ({

theme:state.theme === themes.dark

? themes.light: themes.dark,

}));};

}// . . .

Context

Use the Context.Provider (pt 3)

// . . .render() {

// The ThemedButton button inside the ThemeProvider// uses the theme from state while the one outside uses// the default dark themereturn (

<Page><ThemeContext.Provider value={this.state.theme}>

<Toolbar changeTheme={this.toggleTheme} /></ThemeContext.Provider><Section>

<ThemedButton /></Section>

</Page>);

}}

Context

Read the current Context value

import {ThemeContext} from './theme-context';

class ThemedButton extends React.Component {render() {

let props = this.props;let theme = this.context;return (

<button{...props}style={{backgroundColor: theme.background}}

/>);

}}ThemedButton.contextType = ThemeContext;

export default ThemedButton;

React Hooks

Functions over classes

Hooks

Hooks are a new way of writing React– completely opt-in

– 100% backwards-compatible

– available as of v16.8.0 of React

Hooks

An example of Hooks in action

import React, { useState } from 'react';

function Example() {// Declare a new state variable, which we'll call "count"const [count, setCount] = useState(0);

return (<div>

<p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>

Click me</button>

</div>);

}

Hooks

Hooks ...– are functors that let you "hook into" React state and

lifecycle features from functions

– can be used repeatedly inside of a given function

– don't work inside of classes!

– come "out of the box" and can also be custom-created

Hooks

Hook rules– don't call hooks inside loops, conditions, or nested

functions

– only call hooks from React functions (not from "plain vanilla" JS functions)

Hooks

State hook– simplifies/allows manipulation of state in a React function

component

– import 'useState' from 'react' to use

– call useState() to create a state "tuple"

•pass the initial value for the state•returns a two-element array: the state variable, and the mutator function

– the state variable can be used directly for display

– the mutator function takes the new state to set

Hooks

The state hook in action

import React, { useState } from 'react';

function Example() {// Declare a new state variable, which we'll call "count"const [count, setCount] = useState(0);

return (<div>

<p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>

Click me</button>

</div>);

}

Hooks

Effect hook– perform side effects in function components

data fetching, setting up a subscription, manually changing the DOM

– import 'useEffect' from 'react'

– in essence, useEffect() fires after each and every render()

– if we need to "clean up" when the component unmounts, return a function

this function will be run when the component cleans up (unmounts, goes away, etc)

– there are ways to optimize effects if necessary

Hooks

Effect (adding to the previous example)

function Example() {const [count, setCount] = useState(0);

useEffect(() => {// Update the document title using the browser APIdocument.title = `You clicked ${count} times`;

});

return (<div>

<p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>

Click me</button>

</div>);

}

Hooks

Custom hooks– JavaScript function

– ... whose name starts with "use"

– ... and that may call other hooks

(but don't get crazy with creating new ones until you understand the existing ones really well)

Hooks

Hook takeaways– this will not remove classes from React

– hooks don't replace anything you know of React

– hooks are essentially an AOP attempt by the React team

and how successful they will be in the long term remains to be seen

React Higher-Order Components

Building components out of components

Higher-Order Components

React faces some problems all UI libraries face:– How do we put logging into all our components?

– How do we put data acquisition/release in all our components?

– How do we put easy debugging hints into all our components?

Higher-Order Components

Traditional design has no good answer here– inheritance can't solve the problem

these behaviors need to be implemented in each particular location

– procedural only takes us so far

we can capture some of the behavior into a function but it still needs to be called

– this problem has a name: "cross-cutting concerns"

Higher-Order Components

Aspect-Oriented Programming (AOP) provided a solution– cross-cutting behavior was captured in "aspects"

– aspects described where they would be "woven" (join points)

– aspects could inject behavior before, after or around code

– aspect-weavers would perform all the magic

– horribly complicated

Higher-Order Components

Functional programming provides a different answer– functions can be composed via partial application

– a function that is only partially applied (called) returns a function

not an error

Higher-Order Components

Partial application of an add function

// Haskell-ish examplelet add = function(l, r) { return l + r; };add(1, 2) ==> 3add(1) ==> ???

Higher-Order Components

Partial application of an add function

// Haskell-ish examplelet add = function(l, r) { return l + r; };add(1, 2) ==> 3let increment = add(1)increment(3) ==> 4increment(4) ==> 5

Higher-Order Components

React wants to compose components much the same way– take a component...

– ... pass it into another component...

– ... and that component "decorates" or "composes" the original

Higher-Order Components

Consider: Props logging– we want to log each time React components get props

– React.Component has the componentsWillReceiveProps() lifecycle method

– just write the props out in that method

in every single component that we might want to log

Higher-Order Components

Consider: Props logging– create a higher-order component that "wraps" a passed-in

component

– the HOC defers all code to the passed-in component

– ... except for the componentsWillReceiveProps() method

wherein it logs the props received

Higher-Order Components

Props logging component

function logProps(WrappedComponent) {return class extends React.Component {

componentWillReceiveProps(nextProps) {console.log('Current props: ', this.props);console.log('Next props: ', nextProps);

}render() {

// Wraps the input component in a container, without mutating it. Good!

return <WrappedComponent {...this.props} />;}

}}

Summary

Wrapping up (for now)

Summary

React is...– a highly-opinionated framework

– a highly-productive framework

– growing in popularity

– a very reasonable choice for your web v.Next applications

Summary

Where to go from here?– Redux

this is a common way to do state management across the app

– React Router

for "swapping" components in and out of the UI

– React Native

for building native(-ish) mobile apps using React metaphor

Credentials

Who is this guy?– Director, Platform Strategy -- Quicken Loans

– Principal -- Neward & Associates

– Author

Professional F# 2.0 (w/Erickson, et al; Wrox, 2010)Effective Enterprise Java (Addison-Wesley, 2004)SSCLI Essentials (w/Stutz, et al; OReilly, 2003)Server-Based Java Programming (Manning, 2000)

– Blog: http://blogs.tedneward.com

– Twitter: @tedneward

– For more, see http://www.newardassociates.com

top related